Forum Discussion

David_Horton_20's avatar
David_Horton_20
Icon for Nimbostratus rankNimbostratus
Jan 26, 2007

Connection limits on IP Address

Hi

I am trying to create an iRule to manage traffic based on IP Address. I want to set a limit and only allow that number of people in. My current rule creates an array of ip addresses, when you make a http request your ip gets placed in the array. If the array gets larger than a limit I am setting in the iRule then only people with addresses already in the array get a connection. I remove an IP address from the array when the CLIENT_CLOSED event fires, this usually happens when the client closes their browser or after a period of inactivity.

In my test environment I have the limit set to one and have one tester user using the site(making multiple http requests), if I try and browse the site normally I am denied access, however if I make multiple connection requests using a load testing tool then CLIENT_CLOSED gets fired for the tester user and they are kicked off. If anyone could provide any more information on CLIENT_CLOSED, when and how it gets fired that would be very helpful.

I have put my current iRule in below.

Thanks

Dave


when RULE_INIT {
  array set ::active_IPs { }
  array unset ::active_IPs
  set ::max_active_IPs 1
  set count_active_IPs [array size ::active_IPs]
}
when HTTP_REQUEST {
  set client_ip [IP::remote_addr]
  set count_active_IPs [array size ::active_IPs]
  if { [info exists ::active_IPs($client_ip) ] } {
 pool Active
         return
  } else {
if { $count_active_IPs >= $::max_active_IPs } {
            HTTP::redirect "http://www.busy.com"
} else {
    set ::active_IPs($client_ip) 1  
    pool Active       
}
  }
}
when CLIENT_CLOSED {
  set client_ip [IP::remote_addr]
  if { [info exists ::active_IPs($client_ip)] } {
      unset ::active_IPs($client_ip)
  }
}

5 Replies

  • Colin_Walker_12's avatar
    Colin_Walker_12
    Historic F5 Account
    It might make more sense to place your logic under the CLIENT_CONNECTED event. As it stands now you're performing the check to see how many people are logged in, and if this IP address is one of them, every time the browser sends an HTTP request (possibly hundreds of requests per page), rather than every time a new connection is established.

     

     

    Also...there is a maximum connections setting inherent in the BIG-IP...have you tried using that to set your limits?

     

     

    Colin
  • Thanks Colin, I will definitely investigate using CLIENT_CONNECTED, makes more sense.

     

     

    I am not using the inherent maximum connections settings because I am not sure then how to allow current users to continue their session when the connection limit is reached, the standard functionality seems to arbitrarily deny connections which is not what I want. If I am wrong about this please correct me.

     

     

    Dave
  • Here is an updated (but untested) version which checks the connection limit in CLIENT_ACCEPTED and redirects clients who don't already have an existing connection open to a busy page in HTTP_REQUEST. It might be more graceful to allow clients who have established a previous TCP connection to continue opening new TCP connections. This could be done using the session table.

     
      
      Name : connection limit with HTTP redirect rule 
      
      v1.1 - Aaron Hooley, 30 Sept 2008 
      
      Purpose:  
      
        Limit the number of TCP connections from clients to the virtual server.  When the connection limit is reached,  
           only allow clients who already have an active connection open to the VIP to establish new TCP connections. 
           Clients who establish a new TCP connection after the limit is reached are sent an HTTP redirect to a busy page. 
      
     when RULE_INIT { 
      
         Set the maximum number of TCP connections 
        set ::max_active_IPs 20 
      
         Clear the array if it exists 
        if {[array exists ::active_IPs]}{ 
           array unset ::active_IPs 
        } 
     } 
      
     when CLIENT_ACCEPTED { 
      
         Track whether we'll redirect the client in HTTP_REQUEST 
        set redirect 0 
      
         Check if the current client IP already exists in our array of active client IPs 
        if { [info exists ::active_IPs([IP::client_addr])] } { 
      
            Client exists in the current connection array, so don't redirect them 
           set redirect 0 
      
        } else { 
      
            Client didn't have an existing active TCP connection, so check if there are available connection slots 
           if { [array size ::active_IPs] >= $::max_active_IPs } { 
      
               We're over the connection limit, so redirect the client 
              set redirect 1 
      
           } else { 
      
               We're allowing the client, so add it to the array 
              set ::active_IPs([IP::client_addr]) 1 
      
               Don't redirect the client 
              set redirect 0 
           } 
        } 
     } 
     when HTTP_REQUEST  { 
      
         If the client connection wasn't allowed in CLIENT_ACCEPTED, redirect them here.   
           Tell the client to close the TCP connection with Conenction: Close header in response 
        if {$redirect}{ 
           HTTP::respond 302 "http://busy.example.com" \ 
              "Connection" "Close" \ 
              "Cache-Control" "no-cache" \ 
              "Pragma" "no-cache" 
        } 
     } 
     when CLIENT_CLOSED { 
      
         Client connection was closed, so remove the IP address from the array 
        if { [info exists ::active_IPs([IP::client_addr])] } { 
           unset ::active_IPs([IP::client_addr]) 
        } 
     } 
     

    Aaron
  • Dear hoolio, I am having some error when testing the rules above. Would need your advise as I believed I have done wrongly in any steps.

     

    I got this error in below:

     

    01070151:3: Rule [connection_test] error: line 47: [undefined procedure: Connection] [Connection Clos ] line 48: [undefined procedure: Cache-Control] [Cache-Control no-cach ] line 49: [undefined procedure: Pragma] [Pragma no-cache ]
  • If there is a space after the backslash on these lines, you can remove it to fix the syntax error:

    
           HTTP::respond 302 "http://busy.example.com" \
              "Connection" "Close" \
              "Cache-Control" "no-cache" \
              "Pragma" "no-cache"
    

    Or if it's simpler, you could put it all on one line:

    HTTP::respond 302 "http://busy.example.com" "Connection" "Close" "Cache-Control" "no-cache" "Pragma" "no-cache"

    Aaron