Search code examples
haproxy

HAProxy slow down connections from specific IP


Does anybody know a way of using HAProxy to add incoming requests to a delay once a certain maximum number of requests reached and not just reject or send a status code, actually queue a specific IP address' requests and if not too many, allow once the number has reduced enough.

Using the documentation all the above parts seem possible independently although combined seems to be a problem.

I have the following in my front end:

#Add counter to ip in ratelimiting table
tcp-request content track-sc0 src table ratelimiting

# if alot of requests (more than 1000) - reject
acl mark_alot_of_requests sc0_conn_rate(ratelimiting) gt 1000
tcp-request content reject if mark_alot_of_requests TRUE

#If concurrent requests >= 100 from a single IP return 429
acl mark_too_many_requests sc0_conn_cur(ratelimiting) ge 100
use_backend 429_slow_down if mark_too_many_requests

Then

backend 429_slow_down
    mode http
    timeout tarpit 5s
    reqitarpit .
    errorfile 500 /etc/haproxy/errors/429.http
    http-request tarpit

Is my tarpit that i though did slow them down but doesn't behave in the way I initially thought.

The ratelimiting table is created in the listen as follows:

listen ratelimiting
    mode http
    stick-table type ip size 1m expire 1h store conn_rate(5000),conn_cur

Many thanks


Solution

  • I would use inspect-timeout with 'WAIT_END` in the frontend section

    frontend mywww
    
       tcp-request content track-sc0 src table ratelimiting
    
       acl mark_alot_of_requests sc0_conn_rate(ratelimiting) gt 1000
       tcp-request content reject if mark_alot_of_requests TRUE
    
       acl mark_too_many_requests sc0_conn_cur(ratelimiting) ge 100
    
       # delay for request inspect, it will be used for effectively client delay 
       tcp-request inspect-delay 1000ms
    
       # if client is not too fast let it through
       tcp-request content accept unless mark_too_many_requests
    
       # too fast clients, will need to wait entire inspect-delay
       tcp-request content accept if WAIT_END
    
       use_backend some_normal_backend