Haproxy rate limiting, conn_rate, conn_cur

haproxy

Tried to achieve rate-limiting on haproxy 1.5-18 with the following:

frontend
stick-table type ip size 100k expire 30s store conn_rate(3s)   #connection rate
stick-table type ip size 1m expire 10s store gpc0,http_req_rate(10s) #http req rate
stick-table type ip size 100k expire 30s store conn_cur        #concurrent connections
    tcp-request connection track-sc1 src
    tcp-request connection reject if { sc1_conn_rate ge 20 }
    tcp-request connection reject if { src_get_gpc0(front) gt 50 }
    tcp-request connection reject if { sc1_conn_cur ge 50 }

backend
acl abuse src_http_req_rate(front) ge 10
    acl flag_abuser src_inc_gpc0(front)
    tcp-request content reject if abuse flag_abuser

This would work because the http_req_rate would kick in and ban the abuser. But if I remove the http_req_rate rules and leave only these

frontend
stick-table type ip size 100k expire 30s store conn_rate(3s)   #connection rate
stick-table type ip size 100k expire 30s store conn_cur        #concurrent connections
    tcp-request connection track-sc1 src
    tcp-request connection reject if { sc1_conn_rate ge 50 }
    tcp-request connection reject if { sc1_conn_cur ge 50 }

then an abuser isn't banned, but merely not allowed to launch more than 50 connections. By watching the Apache queue, the "abuser" will keep no more than 50 connections busy.

While this is good because one IP wouldn't max out MaxClients, it is also not best because 5 IPs would – 5*50 = 250, considering MaxClients 250.

Shouldn't the intended behavior be to ban all new and established connections of the abusing IPs?

— please don't point me to the exceliance article, their examples aren't even correct. They exemplified src_conn_cur and src_conn_rate, when they should have used sc1_* (because the prior ones don't work).

Best Answer

if your haproxy is live on the internet (ie, has public IP, not behind firewall, etc).... you could rate limit further down the stack by using iptables...

iptables -I INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --set

iptables -I INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 10 -j DROP

so the haproxy daemon wont even get the traffic, which means more efficiency and less load. this would only work if the haproxy has public ip (not behind amazon elb, for example)