# Simple Connection Rate Limit

**URL:** <https://community.a10networks.com/t/simple-connection-rate-limit/270>\
**Category:** aFleX\
**Created:** [March 11, 2014, 11:11pm UTC](https://community.a10networks.com/t/simple-connection-rate-limit/270 "2014-03-11T23:11:08Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![jmos5156](https://avatars.discourse-cdn.com/v4/letter/j/6bbea6/32.png) [@jmos5156](https://community.a10networks.com/u/jmos5156)\
**Post date:** [March 11, 2014, 11:11pm UTC](https://community.a10networks.com/t/simple-connection-rate-limit/270/1 "2014-03-11T23:11:08Z")

</div>

I’m having some really odd results in using the following aFlex rule. I would expect that the logic would reject inbound requests for a period of 20 seconds following 10 consecutive bad requests. After 5 (not 10) I see the blocks and once the delay time has expired I see the requests fulfilled. However without sending any further bad requests I still get blocked after about 10 sec.

I’m writing direct to the sessions table and incrementing a value. Personally the logic seems right but obviously it’s not. Can someone help?

when RULE\_INIT { set ::BAD\_REQUESTS 10 set ::DELAY 20 }

when HTTP\_REQUEST { set IP [IP::client\_addr] set bad\_request\_limit [table lookup rate\_limit $IP] if {$bad\_request\_limit \>= $::BAD\_REQUESTS} { reject return }

}

when HTTP\_RESPONSE { if {([HTTP::status] == 404) or ([HTTP::status] == 500) or ([HTTP::status] == 503)} { set counter [table lookup rate\_limit $IP] switch $counter { “” { table set rate\_limit $IP 1 indefinite $::DELAY } $::BAD\_REQUESTS { table incr rate\_limit $IP table lifetime rate\_limit $IP $::DELAY } default {table incr rate\_limit $IP} } return } }

---

<div class="post-metadata">

**Author:** ![mischa](https://avatars.discourse-cdn.com/v4/letter/m/b9bd4f/32.png) [@mischa](https://community.a10networks.com/u/mischa)\
**Post date:** [March 12, 2014, 8:47am UTC](https://community.a10networks.com/t/simple-connection-rate-limit/270/2 "2014-03-12T08:47:08Z")

</div>

Try the attached file.

```auto

#################################################
#
# Rate-limit for Failed Requests per timeframe
# (c) A10 Networks -- MP
# v1 20140312
#
#################################################
#
# aFleX script to rate-limit based on requests
# per second and failed responses from the server.
#
# ::MAX_FAILED holds the number of requests that can be
# done before the client is blacklisted.
#
# The ::HOLDTIME_FAILED is the time in seconds.
#
# ::RATE is the amount of requests per timeframe (in seconds)
#
# ::DEBUG can be set to 1, 2 or 3.
#
# Scalability of this aFlex is unknown.
#
# Questions & comments welcome.
# mpeters AT a10networks DOT com
#
#################################################

when RULE_INIT {
  set ::DEBUG 0
  set ::MAX_FAILED 10
  set ::HOLDTIME_FAILED 20
  set ::RATE 2
}

when HTTP_REQUEST {
  set IP [IP::client_addr]
  if { [table lookup blacklist $IP] != "" } {
    reject
    if { $::DEBUG > 1 } { log "$IP -> blacklist expires in [table lifetime blacklist -remaining $IP] seconds" }
    return
  }
  if { [table lookup tmp_blacklist $IP] == "" } {
    table set tmp_blacklist $IP 1
    if { $::DEBUG > 2 } { log "$IP -> request counter created" }
  }
}

when HTTP_RESPONSE {
  if { ([HTTP::status] == 404) or ([HTTP::status] == 500) or ([HTTP::status] == 503) } {
    if { [table lookup tmp_failed $IP] == "" } {
      table set tmp_failed $IP $::RATE
      if { $::DEBUG > 2 } { log "$IP -> failed response counter created" }
    }
  
    set failed_count [table incr tmp_failed $IP]
    if { $::DEBUG > 2 } { log "$IP -> $failed_count of $::MAX_FAILED failed requests" }
    table lifetime tmp_failed $IP $::RATE
  
    if { $failed_count > $::MAX_FAILED } {
      table add blacklist $IP "failed response" indef $::HOLDTIME_FAILED
      if { $::DEBUG >= 1 } { log "$IP -> blacklisted for $::HOLDTIME_FAILED seconds" }
      table delete tmp_failed $IP
      if { $::DEBUG > 2 } { log "$IP -> removed from tmp_failed" }
      return
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![mischa](https://avatars.discourse-cdn.com/v4/letter/m/b9bd4f/32.png) [@mischa](https://community.a10networks.com/u/mischa)\
**Post date:** [March 12, 2014, 8:51am UTC](https://community.a10networks.com/t/simple-connection-rate-limit/270/3 "2014-03-12T08:51:29Z")

</div>

If you want to view what is inside the table you can use the attached file. Bind this to a free VIP or VPORT and use it as: http://[IP]:[PORT]/status:[table\_name] For example: [http://192.168.1.34:8884/status:blacklist](http://192.168.1.34:8884/status:blacklist)

```auto

#################################################
#
# View / Flush contents of a table
# (c) A10 Networks -- MP
# v1 20140312
#
#################################################
#
# aFleX script to view contents of a table with
# the option to flush the complete table.
#
# Scalability of this aFlex is unknown.
#
# Questions & comments welcome.
# mpeters AT a10networks DOT com
#
#################################################

when HTTP_REQUEST {
  set ACTION [getfield [HTTP::uri] ":" 1]
  set TABLE [getfield [HTTP::uri] ":" 2]

  if { $ACTION eq "/flush" } {
    table delete $TABLE -all
    HTTP::respond 200 content "Table $TABLE deleted... <a href=\"/status:$TABLE\">Back to STATUS</a>" Content-Type "text/html"
  } elseif { $ACTION eq "/status" } {
    set response "<html><head><meta http-equiv=\"refresh\" content=\"60\"><title>Contents of Table: $TABLE</title></head>"
    append response "<body><center><h1>Contents of Table: $TABLE</h1><table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">"
    append response "<tr><th>Key</th><th>Value</th></tr>"
    log "TABLE: [table keys $TABLE]"
    set i 0
    foreach tr [table keys $TABLE] {
      incr i
      if { $i == 1 } {
        append response "<tr><td>$tr</td>"
      }
      if { $i == 2 } {
        append response "<td>$tr</td></tr>"
        set i 0
      }
    }
    append response "</table><p>DELETE TABLE: <a href=\"/flush:$TABLE\">$TABLE</a></p>"
    append response "</center></body></html>"
    HTTP::respond 200 content $response Content-Type "text/html"
  } else {
    HTTP::respond 200 content "Usage is prohibited!"
  }
}

```
