Forum Discussion

utahman3431's avatar
utahman3431
Icon for Nimbostratus rankNimbostratus
Mar 26, 2021

Ratelimiting iRule Help

I am trying to create an iRule that will rate limit connections to an exchange autodiscover.xml file. We are coming from a netscaler that will keep the session open if the limit is reached, and allow it to start passing traffic once the rate limiting has timed out. I have almost been able to get this to work with an iRule. I can get the rate limiting to work, but if the threshold has been exceeded the connection closes with an HTTP 403 error (by design). Here is what I have for the iRule:

##  This I-Rule allows only "maxReqs" HTTP requests within "timeout" interval.
##  This version throttles by URI and allows IP address whitelists. IP address can be in 
##  the IP header or the X-Forwarded-For HTTP header.
##
##  This rule requires:
##  A default pool so that the session table can be used and to forward requests.
##
when RULE_INIT {
# This defines the maximum requests to be served within the timing interval defined by the 
    static::timeout variable below. 
    set static::maxReqs 1000;
# Timer Interval in seconds within which only static::maxReqs Requests are allowed.  
# (i.e: 10 req per 2 sec == 5 req per sec) 
# If this timer expires, it means that the limit was not reached for this interval and the request 
# counting starts over.
# Making this timeout large increases memory usage.  Making it too small negatively affects performance.  
    set static::timeout 1;
}
when HTTP_REQUEST {
    if { [class match [HTTP::uri] equals URIs_to_throttle] } {
# The following expects the IP addresses in multiple X-forwarded-for headers.  It picks the first one.
        if { [HTTP::header exists X-forwarded-for] } {
            set client_IP_addr [getfield [lindex  [HTTP::header values X-Forwarded-For]  0] "," 1]
        }
        else {
            set client_IP_addr [IP::client_addr]
        }
# The matching below expects a datagroup named: Throttling_Whitelist_IPs
# The Condition of the if statement is true if the IP address is NOT in the whitelist.
        if { not ([class match $client_IP_addr equals Throttling_Whitelist_IPs ] )} {
            set getcount [table lookup -notouch $client_IP_addr]
            if { $getcount equals "" } {
                table set $client_IP_addr "1" $static::timeout $static::timeout
# record of this session does not exist, starting new record, request is allowed.
                }
            else {
                    if { $getcount < $static::maxReqs } {
                        log local0. "Request Count for $client_IP_addr is $getcount"  
                        table incr -notouch $client_IP_addr
# record of this session exists but request is allowed.
                    }
                    else {
                        HTTP::respond 403 content {
                            <html>
                                <head>
                                    <title>HTTP Request denied</title>
                                </head>
                                <body>Your HTTP requests are being throttled.</body>
                            </html>
                        }
                    }
                }
            }
    }
}

I was looking at using something with the after command, but am still not sure how to go about implementing it. I was thinking of doing something like this in that last else statement:

}else {
  while {$getcount > $static::maxReqs} {
    after 1000
    incr $getcount -1
  }
}

Would something like this work? I don't have access to implement this at this moment, but would be something that I put into place probably in the next week or so.

3 Replies

    • utahman3431's avatar
      utahman3431
      Icon for Nimbostratus rankNimbostratus

      I've looked into those, and it appears that rate limiting classes and traffic classes are applied from a VS context and affects the amount of traffic going through the entire VS. I am trying to get this narrowed down to a per user basis.

      I'm still a little new to creating my own iRules, but there's got to be something that will let a session stay open until a table count threshold has been met.

      • Nikoolayy1's avatar
        Nikoolayy1
        Icon for MVP rankMVP

        About rate class it should be applied only to packets matching the iRule if statement not every packet for the VIP will be affected.

         

        Try looking into https://support.f5.com/csp/article/K14813 and "Understanding iRule mitigation" that has a SIP example that you may try to modify for your needs.