Forum Discussion

bezeqint's avatar
bezeqint
Icon for Nimbostratus rankNimbostratus
Mar 06, 2012

iRule to mitigate attack

hello,

 

 

i need to protect mail servers from a virus attack.

 

we have a network with users. some of them are using the mail servers, some of them are attacking the mail servers. we see that some users create 4000 short connection to the mail servers - the concurrent connection for each user is 1.

 

 

what i would like to do is:

 

1. if a user a part of a network that belongs to a group, he can open, lets say, 10 new connections per second (not concurrent! the rate of opening a tcp connection - a user can keep 500 connections, but can create only 10 new per second)

 

2. the rest of the users can open connections at any rate.

 

 

can i do that using iRule?

 

can iRule limit the rate of opening new connections?

 

 

how do i write something like that?

 

 

6 Replies

  • Hi,

     

     

    have a look here, where hoolio is showing a clever example to rate limit new connections.

     

    https://devcentral.f5.com/wiki/iRul...ables.ashx

     

     

    You could just change the logic of this that you move the code in the CLEINT_ACCEPTED event into the if statement, so you can have a client greylist, in which you put your networks.

     

     

    if you want to add the limit concurrency from clients, this thread is a good start:

     

    https://devcentral.f5.com/Community...fault.aspx

     

     

    Hope this helps,

     

     

    Christian
  • the first link limit connection per virt - this is not what i'm looking for.

    the second link is much better.

    i've edit the irule and it looks something like this:

    what happend to other networks (outside the datagroup)? they wont be limited?

     
     Data group mapping hosts/networks to connection limit values
    class conn_limit_dg {
       network 10.0.0.0/8 { "2" }
    }
    
    when RULE_INIT {
         This defines how long is the sliding window to count the requests. This example allows 10 requests in 3 seconds
        set static::windowSecs 3
    }
    when CLIENT_ACCEPTED {
    
         Max connections per client IP
        set limit [class match -value [IP::client_addr] equals conn_limit_dg]
        log local0. "[IP::client_addr]: \$limit: $limit"
    
         Check if client IP is in the connection limit data group and the request is a GET
        if { $limit ne "" } {
            set getCount [table key -count -subtable [IP::client_addr]]
            log local0. "[IP::client_addr]: getCount=$getCount"
            if { $getCount < $limit} {
                incr getCount 1
                table set -subtable [IP::client_addr] $getCount "" indefinite $static::windowSecs
            } else {  log local0. "[IP::client_addr]: exceeded the number of requests allowed. $getCount / $limit"
               reject
            }
        }
    }
     

  • Here's an optimized version which limits each client to X concurrent connections:

    
     Purpose: Limit each client to X concurrent connections
    when RULE_INIT {
         Max number of connections for a client over an interval
        set static::max_conns 10
         Log debug to /var/log/ltm? 1=yes, 0=no
        set static::conn_debug 1
    }
    when CLIENT_ACCEPTED {
         Use a subtable name specific to the client IP
        set subtable "connlimit:[IP::client_addr]"
         Add the client port to the client IP-specific subtable with a 65 second timer 
         and an indefinite timeout.  We use the after command to touch the key every 60 seconds
         as long as the connection is open.
         The subtable entry is removed when the connection is closed.
        table set -subtable $subtable [TCP::client_port] "" 65 indefinite
        if {$static::conn_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Added new key [TCP::client_port],\
            count: [table keys -subtable $subtable -count], max: $static::max_conns"}
         Set a timer to update the subtable entry every Y milliseconds
        set timer [after 60000 -periodic {
            table lookup -subtable $subtable [TCP::client_port]
            if {$static::conn_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Touched key [TCP::client_port] using after script"}
        }]
         Check if the subtable has over X entries
        set count [table keys -subtable $subtable -count]
        if { $count >= $static::max_conns } {
            if {$static::conn_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Over limit count: $count / limit: $static::max_conns"}
             Drop the connection
            drop
             Or apply a rateclass
             rateclass rateclass1
        }
    }
    when CLIENT_CLOSED {
         When the client connection is closed, remove the subtable entry
        table delete -subtable $subtable [TCP::client_port]
        if {$static::conn_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Deleting key [TCP::client_port]"}
         Cancel the timer
        if {[info exists timer] && $timer ne ""}{
            if {$static::conn_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Cancelling timer $timer"}
            after cancel $timer
        }
    }

    Aaron
  • Actually, it looks like you want to limit new connections per second per client IP. I'll test something today for this as the above example wouldn't help for your scenario.

     

     

    Aaron
  • I did basic functional testing of this iRule. It would be great if you could do some performance testing for it and let me know if you see any issues. I'm particularly interested in seeing what increase in TMM CPU and memory utilization you see.

    Thanks, Aaron

    
     Purpose: Limit each client to X connections per second
    when RULE_INIT {
     Max number of connections per client IP per second
    set static::max_conns 10
    
     Log debug to /var/log/ltm? 1=yes, 0=no
    set static::conn_debug 1
    }
    when CLIENT_ACCEPTED {
    
     Use a subtable name specific to the client IP and current second
    set subtable "connlimit:[IP::client_addr]_[clock seconds]"
    
     Add the client port to the client IP-specific subtable with a 2 second timer and timeout.
     For counting we don't care if the subtable has extra entries as we move onto a new subtable every second.
    table set -subtable $subtable [TCP::client_port] "" 2 2
    if {$static::conn_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Added new key [TCP::client_port]\
    to table, $subtable, count: [table keys -subtable $subtable -count] / max: $static::max_conns"}
    
     Check if the subtable has over X entries
    set count [table keys -subtable $subtable -count]
    if { $count >= $static::max_conns } {
    
    if {$static::conn_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Over limit count: $count / max: $static::max_conns"}
    
     Drop the connection
    drop
    
     Or apply a rateclass
     rateclass rateclass1
    
    }
    }
    
  • i need to limit only specific networks, also, datagroups are preferable.

     

    can you create and flush a table (such as code below) for specific networks?

     

     

    what about the code that i posted, it wont work? what's the advantages of your code?