Forum Discussion

lstewart_53611's avatar
lstewart_53611
Icon for Nimbostratus rankNimbostratus
Apr 21, 2010

Limiting number of connected clients

I am trying to write a rule to limit the number of individual clients that can connect to a VS, but not limit the total number of connections that they can have. After that limit has been reached, additional attempted connections should be dropped. So say 1000 clients (individual IPs) connect, any requests from additional clients are rejected, while any requests from already-connected clients are fine.

 

 

I think I might need to get some persistence in on the action, but I'm not sure if that's the best way to go about it. I think what I have hear will actually limit the number of total connections rather than the number of clients:

 

 

when RULE_INIT {

 

set ::connectedclients { }

 

}

 

when CLIENT_ACCEPTED {

 

set client_ip [IP::remote_addr]

 

if { [info exists ::connectedclients] } {

 

if {$::connectedclients > 1000 } {

 

reject

 

return

 

} else {

 

incr ::connectedclients

 

}

 

} else {

 

set ::connected 1

 

}

 

}

 

when CLIENT_CLOSED {

 

if { [info exists ::connectedclients] } {

 

incr ::connectedclients -1

 

if { $::connectedclients <= 0 } {

 

unset ::connectedclients

 

}

 

}

 

}

 

 

 

The client_ip variable is unused above, though it needs to be used. I don't want to try to keep a list of 1000 IPs to check through, obviously. Any ideas? I thought of setting IP persistence and limiting the total to 1000 in that fashion, but there's no real way for me to decrement the connected users in tat way. However, I can abandon that portion and only allow 1000 clients to connect in a certain time period.

7 Replies

  • check this code share rule:

     

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/HTTPRequestThrottle.html

     

  • Ian - the linked rule is still trying to limit the number of connections per client. What I'm trying to do is limit the number of clients without limiting the connections per client. I'm not coming up with an elegant (or just quick) way to store a list of a fairly large (I'm using 1000 in my example) number of client_ip entries to check against to see if connections from that client are allowed and to not allow further clients once the quota is full.
  • I think tracking 1000 client IPs is necessary if you want to allow the first 1000 clients to open as many connections as they try to. Here is an iRule which should support your scenario. It tracks the client IP and count of concurrent TCP connections. This way the client can open multiple connections. The client IP is removed from the array when their last connection is closed.

    I didn't test it so let me know if you run into any issues when you test it.

    Aaron

    
    when RULE_INIT {
        Initialize a new array of client IP addresses
       set ::clients { }
    }
    when CLIENT_ACCEPTED {
    
        Check if the client IP is already in the array
       if {[info exists ::clients([IP::client_addr])]}{
    
           Client already exists in the array, so increment the connection count
          incr ::clients([IP::client_addr])
    
       } else {
    
           Client IP isn't in the array, so check if we're under the limit
          if {[array size ::clients] < 1000}{
    
              Allowing this client, so add them the array with one connection counted
             set ::clients([IP::client_addr]) 1
    
          } else {
    
              We're over the limit, so reject the connection
             reject 
          }
       }
    }
    when CLIENT_CLOSED {
        Check if the client IP is in the array (this should always be true)
       if {[info exists ::clients([IP::client_addr])]}{
    
           Decrement the count
          incr ::clients([IP::client_addr]) -1
    
           If the count is less than 1, remove the client IP from the array
          if {$::clients([IP::client_addr]) < 1}{
             unset ::clients([IP::client_addr])
          }
       }
    }
    

  • Oh, this is exaclty what I'm looking for, but the above code is not working for me.

     

    I'm running 10.2.1 473, and get this error in the LTM logfile:

     

     

    - can't set "::clientcount(10.0.14.241)": variable isn't array while executing "set ::clientcount([IP::client_addr]) 1"

     

     

    This iRule is meant to "slow start" our site after we had mainenance, to only let a few people warm up the caches and stuff on the app servers.

     

     

    So, what I'm really looking for is a way to limit the number of unique visitors, and increase this value if needed. They should have full access to the site if they arrive and get's an "open slot" in the array, and if the array if full, we will present the maintenace page instead.

     

     

    Any suggestions on an already developed and working iRule for this scenario?

     

     

    Regards // C
  • there is an example irule to limit a vip to a number of connections in the following article. the best thing is that it is cmp compatible. is it applicable for your situation?

     

     

    v10.1 - The table Command - Counting by Spark

     

    http://devcentral.f5.com/Tutorials/TechTips/tabid/63/articleType/ArticleView/articleId/2381/v101--The-table-Command--Counting.aspx

     

     

    hope this helps.
  • Thanks.

     

    I don't really want to limit the number of connection, rather than the numer of unique visitors. (IP's)

     

    We run a very popular site, where ppl login and brows 'round. If i limit the number of connection, an already logged in user might lose a connection during something, and a user not logged in might get a connection.

     

     

    Was really hoping the above piece of code would work, since it's exactly what i want to accomplish =)
  • i revised the table command's example a little bit. may it be usable?

    [root@ve1023:Active] config  b virtual bar list
    virtual bar {
       snat automap
       pool foo
       destination 172.28.65.152:ssh
       ip protocol tcp
       rules myrule
    }
    [root@ve1023:Active] config  b rule myrule list
    rule myrule {
       when CLIENT_ACCEPTED {
       event CLIENT_CLOSED disable
    
    set tbl "clientlimit"
    set key "[IP::client_addr]"
    
            log local0. "[IP::client_addr]:[TCP::client_port]|[table keys -subtable $tbl]|[table keys -subtable $tbl -count]"
    
            if {[table lookup -subtable $tbl $key] equals ""} {
                    if {[table keys -subtable $tbl -count] > 0} {
                            reject
                            log local0. "[IP::client_addr]:[TCP::client_port] is rejected"
                    } else {
                            table set -subtable $tbl $key "ignored" 180
                            set timer [after 60000 -periodic {table lookup -subtable $tbl $key}]
                            event CLIENT_CLOSED enable
                    }
            }
    }
    
    when CLIENT_CLOSED {
        after cancel $timer
        table delete -subtable $tbl $key
    }
    }
    
    [root@ve1023:Active] config  tail -f /var/log/ltm
    Nov 15 08:27:58 local/tmm info tmm[4766]: Rule myrule : 192.168.204.7:53985||0
    Nov 15 08:28:05 local/tmm info tmm[4766]: Rule myrule : 192.168.204.7:53989|192.168.204.7|1
    Nov 15 08:28:15 local/tmm info tmm[4766]: Rule myrule : 192.168.204.7:53991|192.168.204.7|1
    Nov 15 08:28:24 local/tmm info tmm[4766]: Rule myrule : 172.28.17.30:56279|192.168.204.7|1
    Nov 15 08:28:24 local/tmm info tmm[4766]: Rule myrule : 172.28.17.30:56279 is rejected