]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] acl: add 2 new verbs: fe_sess_rate and be_sess_rate
authorWilly Tarreau <w@1wt.eu>
Thu, 5 Mar 2009 20:34:28 +0000 (21:34 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 5 Mar 2009 20:34:28 +0000 (21:34 +0100)
These new ACLs match frontend session rate and backend session rate.
Examples are provided in the doc to explain how to use that in order
to limit abuse of service.

doc/configuration.txt
src/backend.c

index 84465e82bb9db0d13c0ad42aa4bf5c025346a623..24bf1bc861b42162e9e760db214282d83f88f0a9 100644 (file)
@@ -4070,6 +4070,44 @@ connslots(backend) <integer>
   dynamic connections. Also, if any of the server maxconn, or maxqueue is 0, then
   this acl clearly does not make sense - in which case the value returned will be -1.
 
+fe_sess_rate <integer>
+fe_sess_rate(frontend) <integer>
+  Returns true when the session creation rate on the current or the named
+  frontend matches the specified values or ranges, expressed in new sessions
+  per second. This is used to limit the connection rate to acceptable ranges in
+  order to prevent abuse of service at the earliest moment. This can be
+  combined with layer 4 ACLs in order to force the clients to wait a bit for
+  the rate to go down below the limit.
+
+  Example :
+        # This frontend limits incoming mails to 10/s with a max of 100
+        # concurrent connections. We accept any connection below 10/s, and
+        # force excess clients to wait for 100 ms. Since clients are limited to
+        # 100 max, there cannot be more than 10 incoming mails per second.
+        frontend mail
+            bind :25
+            mode tcp
+            maxconn 100
+            acl too_fast fe_sess_rate ge 10
+            tcp-request inspect-delay 100ms
+            tcp-request content accept if ! too_fast
+            tcp-request content accept if WAIT_END
+  
+be_sess_rate <integer>
+be_sess_rate(backend) <integer>
+  Returns true when the sessions creation rate on the backend matches the
+  specified values or ranges, in number of new sessions per second. This is
+  used to switch to an alternate backend when an expensive or fragile one
+  reaches too high a session rate, or to limite abuse of service (eg. prevent
+  sucking of an online dictionary).
+
+  Example :
+        # Redirect to an error page if the dictionary is requested too often
+        backend dynamic
+            mode http
+            acl being_scanned be_sess_rate gt 100
+            redirect location /denied.html if being_scanned
+
 
 2.3.5.2) Matching contents at Layer 4
 -------------------------------------
index 73fb1129f76bcb33311c36cd397f75e1a5150d80..d386805ebb8956690ec86280e3d42f8fa819bf0e 100644 (file)
@@ -2096,11 +2096,51 @@ acl_fetch_connslots(struct proxy *px, struct session *l4, void *l7, int dir,
        return 1;
 }
 
+/* set test->i to the number of connections per second reaching the frontend */
+static int
+acl_fetch_fe_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
+                       struct acl_expr *expr, struct acl_test *test)
+{
+       test->flags = ACL_TEST_F_VOL_TEST;
+       if (expr->arg_len) {
+               /* another proxy was designated, we must look for it */
+               for (px = proxy; px; px = px->next)
+                       if ((px->cap & PR_CAP_FE) && !strcmp(px->id, expr->arg.str))
+                               break;
+       }
+       if (!px)
+               return 0;
+
+       test->i = read_freq_ctr(&px->fe_sess_per_sec);
+       return 1;
+}
+
+/* set test->i to the number of connections per second reaching the backend */
+static int
+acl_fetch_be_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
+                       struct acl_expr *expr, struct acl_test *test)
+{
+       test->flags = ACL_TEST_F_VOL_TEST;
+       if (expr->arg_len) {
+               /* another proxy was designated, we must look for it */
+               for (px = proxy; px; px = px->next)
+                       if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
+                               break;
+       }
+       if (!px)
+               return 0;
+
+       test->i = read_freq_ctr(&px->be_sess_per_sec);
+       return 1;
+}
+
 
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct acl_kw_list acl_kws = {{ },{
        { "nbsrv",    acl_parse_int,   acl_fetch_nbsrv,     acl_match_int, ACL_USE_NOTHING },
        { "connslots", acl_parse_int,   acl_fetch_connslots, acl_match_int, ACL_USE_NOTHING },
+       { "fe_sess_rate", acl_parse_int, acl_fetch_fe_sess_rate, acl_match_int, ACL_USE_NOTHING },
+       { "be_sess_rate", acl_parse_int, acl_fetch_be_sess_rate, acl_match_int, ACL_USE_NOTHING },
        { NULL, NULL, NULL, NULL },
 }};