bchick2_8645
Nov 21, 2011Nimbostratus
Limit Client Connections with Table
We have been using (verbatim) the iRule given on the Wiki at Click Here to successfully limit the number of concurrent connections from a single source IP address. However, we recently learned the use of global variables in the rule was demoting our LTM 1600 out of CMP mode. Some research seemed to indicate that replacing the global array with the new (at least new to me) table command was the right approach. I took a first shot at that and it seemed to be working fine at first but recently we started receiving log messages as follows:
Unable to resume pending rule event CLIENT_CLOSED on closed flow XXX.XXX.XXX.XXX:XXXX->YYY.YYY.YYY.YYY:443
Where the X's are the client source IP address / port and the Y's are the server IP. This wasn't happening at first but started over time. Didn't notice it before the upgrade from 10.2.2 HF3 to 10.2.3 but won't swear that it didn't start until then. Searching devcentral and the support site I can't find any hits on that particular log entry. Can anybody tell me what I might be doing wrong? I'm pasting the text of the iRule below, any help confirming the validity of the iRule or pointers for improving it would be greatly appreciated.
Thanks in advance.
when RULE_INIT {
The maximum number of TCP connections to the virtual server from a single client IP address
set static::max_connections_per_ip 1000
Table name (will later be appended with VS name)
set static::tbl "vsratelimit"
}
when CLIENT_ACCEPTED {
If client IP is exempted skip the rest of the rule and return
if {[class match [IP::client_addr] equals concurrent_sessions_exemptions]} {
return
}
Set the key to the client IP
set key "[IP::client_addr]"
Append the VS name to the end of the table name
set tbl ${static::tbl}_[virtual name]
If the IP is already in the table increment the count
if {[table keys -subtable $tbl] contains $key} {
set value [table lookup -subtable $tbl $key]
Check if over the max connection limit and if so reject
if {$value >= $static::max_connections_per_ip} {
log local0. "Max connections exceeded for IP: $key, rejecting connection"
reject
} else {
Increment the connection count
table incr -subtable $tbl $key
Only for debug:
log local0. "Count for $key incremented to $value"
}
} else {
IP is not already in the table so add it with count 1
table set -subtable $tbl $key 1 indef
log local0. "Key added to table for $key"
}
}
when CLIENT_CLOSED {
If client IP is exempted skip the rest of the rule and return
if {[class match [IP::client_addr] equals concurrent_sessions_exemptions]} {
return
}
Set the key to the client IP
set key "[IP::client_addr]"
Append the VS name to the end of the table name
set tbl ${static::tbl}_[virtual name]
Check if the client has a count in the table
if {[table keys -subtable $tbl] contains $key} {
Decrement the count by 1
table incr -subtable $tbl $key -1
Check if the count is 0 or negative
set value [table lookup -subtable $tbl $key]
log local0. "Count for $key decremented to $value"
if {$value <= 0} {
Clear the table entry
table delete -subtable $tbl $key
log local0. "Table entry deleted for $key"
}
}
}