]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] config: parse tcp layer4 rules (tcp-request accept/reject)
authorWilly Tarreau <w@1wt.eu>
Sun, 23 May 2010 20:40:30 +0000 (22:40 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 14 Jun 2010 08:53:12 +0000 (10:53 +0200)
These rules currently only support the "accept" and "reject" actions.
They will apply on pure layer 4 and will not support any content.

doc/configuration.txt
src/proto_tcp.c

index 240a54898069d33c3ba819048ba18c9ae7c5c5e1..7aa12a71a9300e3a42ea56a478c4ed123f023ace 100644 (file)
@@ -907,9 +907,11 @@ stick match                               -          -         X         X
 stick on                                  -          -         X         X
 stick store-request                       -          -         X         X
 stick-table                               -          -         X         X
+tcp-request accept                        -          X         X         -
 tcp-request content accept                -          X         X         -
 tcp-request content reject                -          X         X         -
 tcp-request inspect-delay                 -          X         X         -
+tcp-request reject                        -          X         X         -
 timeout check                             X          -         X         X
 timeout client                            X          X         X         -
 timeout clitimeout          (deprecated)  X          X         X         -
@@ -5061,6 +5063,38 @@ stick-table type {ip | integer | string [len <length>] } size <size>
              about time format.
 
 
+tcp-request accept [{if | unless} <condition>]
+  Accept an incoming connection if/unless a layer 4 condition is matched
+  May be used in sections :   defaults | frontend | listen | backend
+                                 no    |    yes   |   yes  |   no
+
+  Immediately after acceptance of a new incoming connection, it is possible to
+  evaluate some conditions to decide whether this connection must be accepted
+  or dropped. Those conditions cannot make use of any data contents because the
+  connection has not been read from yet, and the buffers are not yet allocated.
+  This can be used to selectively and very quickly accept or drop connections
+  from various sources with a very low overhead. If some contents need to be
+  inspected in order to take the decision, the "tcp-request content" statements
+  must be used instead.
+
+  This statement accepts the connection if the condition is true (when used
+  with "if") or false (when used with "unless"). It is important to understand
+  that "accept" and "reject" rules are evaluated in their exact declaration
+  order, so that it is possible to build complex rules from them. There is no
+  specific limit to the number of rules which may be inserted.
+
+  Note that the "if/unless" condition is optional. If no condition is set on
+  the action, it is simply performed unconditionally.
+
+  If no "tcp-request" rules are matched, the default action is to accept the
+  connection, which implies that the "tcp-request accept" statement will only
+  make sense when combined with another "tcp-request reject" statement.
+
+  See section 7 about ACL usage.
+
+  See also : "tcp-request reject" and "tcp-request content"
+
+
 tcp-request content accept [{if | unless} <condition>]
   Accept a connection if/unless a content inspection condition is matched
   May be used in sections :   defaults | frontend | listen | backend
@@ -5164,6 +5198,45 @@ tcp-request inspect-delay <timeout>
              "timeout client".
 
 
+tcp-request reject [{if | unless} <condition>]
+  Reject an incoming connection if/unless a layer 4 condition is matched
+  May be used in sections :   defaults | frontend | listen | backend
+                                 no    |    yes   |   yes  |   no
+
+  Immediately after acceptance of a new incoming connection, it is possible to
+  evaluate some conditions to decide whether this connection must be accepted
+  or dropped. Those conditions cannot make use of any data contents because the
+  connection has not been read from yet, and the buffers are not yet allocated.
+  This can be used to selectively and very quickly accept or drop connections
+  from various sources with a very low overhead. If some contents need to be
+  inspected in order to take the decision, the "tcp-request content" statements
+  must be used instead.
+
+  This statement rejects the connection if the condition is true (when used
+  with "if") or false (when used with "unless"). It is important to understand
+  that "accept" and "reject" rules are evaluated in their exact declaration
+  order, so that it is possible to build complex rules from them. There is no
+  specific limit to the number of rules which may be inserted.
+
+  Note that the "if/unless" condition is optional. If no condition is set on
+  the action, it is simply performed unconditionally.
+
+  If no "tcp-request" rules are matched, the default action is to accept the
+  connection, which implies that the "tcp-request accept" statement will only
+  make sense when combined with another "tcp-request reject" statement.
+
+  Rejected connections are accounted in stats but are not logged. The reason is
+  that these rules should only be used to filter extremely high connection
+  rates such as the ones encountered during a massive DDoS attack. Under these
+  conditions, the simple action of logging each event would make the system
+  collapse and would considerably lower the filtering capacity. If logging is
+  absolutely desired, then "tcp-request content" rules should be used instead.
+
+  See section 7 about ACL usage.
+
+  See also : "tcp-request accept" and "tcp-request content"
+
+
 timeout check <timeout>
   Set additional check timeout, but only after a connection has been already
   established.
index fc020c969fe1a7cf50abd46a4c41102baf28c42e..b753c3bbd483d3a7e12e7ec130e1974d1b479642 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp)
  *
- * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -717,6 +717,11 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
        const char *ptr = NULL;
        unsigned int val;
        int retlen;
+       int action;
+       int warn = 0;
+       int pol = ACL_COND_NONE;
+       struct acl_cond *cond;
+       struct tcp_rule *rule;
 
        if (!*args[1]) {
                snprintf(err, errlen, "missing argument for '%s' in %s '%s'",
@@ -758,12 +763,6 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
        }
 
        if (!strcmp(args[1], "content")) {
-               int action;
-               int warn = 0;
-               int pol = ACL_COND_NONE;
-               struct acl_cond *cond;
-               struct tcp_rule *rule;
-
                if (curpx == defpx) {
                        snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
                                 args[0], args[1]);
@@ -819,9 +818,69 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
                return warn;
        }
 
-       snprintf(err, errlen, "unknown argument '%s' after '%s' in %s '%s'",
-                args[1], args[0], proxy_type_str(proxy), curpx->id);
-       return -1;
+       /* OK so we're in front of plain L4 rules */
+       if (!strcmp(args[1], "accept"))
+               action = TCP_ACT_ACCEPT;
+       else if (!strcmp(args[1], "reject"))
+               action = TCP_ACT_REJECT;
+       else {
+               retlen = snprintf(err, errlen,
+                                 "'%s' expects 'inspect-delay', 'content', 'accept' or 'reject', in %s '%s' (was '%s')",
+                                 args[0], proxy_type_str(curpx), curpx->id, args[1]);
+               return -1;
+       }
+
+       if (curpx == defpx) {
+               snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
+                        args[0], args[1]);
+               return -1;
+       }
+
+       pol = ACL_COND_NONE;
+       cond = NULL;
+
+       if (strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0) {
+               if ((cond = build_acl_cond(NULL, 0, curpx, (const char **)args+2)) == NULL) {
+                       retlen = snprintf(err, errlen,
+                                         "error detected in %s '%s' while parsing '%s' condition",
+                                         proxy_type_str(curpx), curpx->id, args[2]);
+                       return -1;
+               }
+       }
+       else if (*args[2]) {
+               retlen = snprintf(err, errlen,
+                                 "'%s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
+                                 args[0], args[1], proxy_type_str(curpx), curpx->id, args[2]);
+               return -1;
+       }
+
+       if (cond && (cond->requires & (ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY))) {
+               struct acl *acl;
+               const char *name;
+
+               acl = cond_find_require(cond, ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY);
+               name = acl ? acl->name : "(unknown)";
+
+               if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) {
+                       retlen = snprintf(err, errlen,
+                                         "'%s %s' may not reference acl '%s' which makes use of payload in %s '%s'. Please use '%s content' for this.",
+                                         args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]);
+                       return -1;
+               }
+               if (acl->requires & ACL_USE_RTR_ANY)
+                       retlen = snprintf(err, errlen,
+                                         "acl '%s' involves some response-only criteria which will be ignored.",
+                                         name);
+
+               warn++;
+       }
+
+       rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
+       rule->cond = cond;
+       rule->action = action;
+       LIST_INIT(&rule->list);
+       LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list);
+       return warn;
 }