Forum Discussion

Alexander_Kwong's avatar
Alexander_Kwong
Icon for Nimbostratus rankNimbostratus
Nov 21, 2013

how to limit a client IP from continuously opening connections to the server

Hi guys, I'm a noob to iRules and was wondering if there was a way we could write up an iRule to limit the amount of connections a user can open over a course of a period of time. We got hammered by one user that continuously tried to make connections to a server just to download a pdf file we had online. So to mitigate the issue, we want to see if we limit that one user from overloading our servers with requests and taking them down, without denying them access completely.

We did a search and we found this iRule that seems to be kind of what we are looking for. Is this the correct iRule to use in our environment. A few things to know, is that we have a OneConnect and X_Forward_For profile setup, in addition, we are using SNAT Automap.

Please let me know. Thanks in advance for your help.

when RULE_INIT { 

 this is the life timer of the subtable object. defines how long this object exist in the subtable 
set static::maxRate 120
 This defines how long is the sliding window to count the requests. This example allows 30 requests in 3 seconds 
set static::windowSecs 3 
set static::timeout 30 
 This turns on/off debug logging (0 = off, 1 = on)
set DEBUG 1
} 
when HTTP_REQUEST { 
if { ([HTTP::method] eq "GET") and ([string tolower [HTTP::header "User-Agent"]] contains "android" )}
{ 
set getCount [table key -count -subtable [IP::client_addr]] 
if { $DEBUG } { log local0. "getCount=$getCount" }
if { $getCount < $static::maxRate } { 
incr getCount 1 
table set -subtable [IP::client_addr] $getCount "ignore" $static::timeout $static::windowSecs 
} else { 
if { $DEBUG } { log local0. “This IP: [IP::client_addr] has exceeded the number of requests allowed. ” }
HTTP::respond 501 content "We apologize but your request/sec limit has exceeded the set threshold.  Please wait 30 seconds and refresh the page." 

return 
} 
} 
}

7 Replies

  • Pascal_Tene_910's avatar
    Pascal_Tene_910
    Historic F5 Account

    The above iRule seems to be dealing with android(mobile client). if you know the specific client IP which is causing trouble, you might just want to block that one.

     

    otherwise, you might want to try the irule at this link.

     

    https://devcentral.f5.com/questions/help-need-to-create-a-irule-for-limit-client-connection (it might need to be tuned in order to match your specific requirements). This irule is more generic and filters at layer 4 (more efficient) rather than layer 7 like the one you posted.

     

  • Pascal_Tene_910's avatar
    Pascal_Tene_910
    Historic F5 Account

    the link:

     

    https://devcentral.f5.com/questions/how-to-limit-a-client-ip-from-continuously-opening-connections-to-the-server

     

  • Hi Pascal, Thank you for your reply... I was reading up on the link and this is where we got our iRule from and we just tweaked it to include the Android lookup to apply the iRule only to those devices.

     

    Actually the IP varies and is not always from the same user. But one thing in common was that the user was using an Android device when this happens.

     

    So from what you are suggesting, it sounds like this iRule should work in our situation?

     

    Thanks again.

     

  • Looks good to me but the rule relates to HTTP requests, not TCP connections - I assume that's OK. Also, don't forget to turn off the DEBUG when you put this into production.

     

  • John_Alam_45640's avatar
    John_Alam_45640
    Historic F5 Account

    Here is a better version of this irule.

    when RULE_INIT {

     This is the max requests allowed during "interval" specified below.
    
    set static::maxRate 10;
    
     Below is the lifetime of the subtable record in seconds. 
     This defines the interval during which requests are tallied. Example: Rate=10 and Timeout=3, allows 10 requests in 3 seconds 
     Note: do not use very high timeout because it increases memory utilization especially under high load. 
     Note: A rate of 100 in 50 seconds is the same is a rate of 20 in 1 second. But 1 second is a lot easier on memory, 
     Because the records expire more quickly and the table does become too large.
    set static::timeout 3;
    

    }

    when HTTP_REQUEST {

        set getCount [table lookup -notouch -subtable requests [IP::client_addr]]
                if { $getCount equals "" } {
                    log local0. "New one:  getCount=$getCount [IP::client_addr] [clock seconds]"
                    table set -subtable requests [IP::client_addr] "1" $static::timeout $static::timeout
                } else {
    
                if { $getCount < $static::maxRate } {
                    table incr -notouch -subtable requests [IP::client_addr]
    
                } else {
                    if {$getCount == $static::maxRate } {
                        log local0. "User @ [IP::client_addr] [clock seconds] has reached $getCount in $static::timeout seconds."
                       table incr -notouch -subtable requests [IP::client_addr]
                    }
                    HTTP::respond 501 content "Request blocked Exceeded requests/sec limit."
                    drop
                    return
                }
    
                }
    

    }

    • Alexander_Kwong's avatar
      Alexander_Kwong
      Icon for Nimbostratus rankNimbostratus
      Sorry forgot to mention that we tested it out and it works, however, after a few refreshes on the webpage from the same client, we get the "Request blocked" message. So my question is, if we are using SNAT and multiple clients connect, will this block other legitimate users that access the site at the same time? Or does this filter only by real client IP address (not NAT'ed).