]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] frontend: check for LI_O_TCP_RULES in the listener
authorWilly Tarreau <w@1wt.eu>
Mon, 31 May 2010 08:30:33 +0000 (10:30 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 14 Jun 2010 08:53:13 +0000 (10:53 +0200)
The new LI_O_TCP_RULES listener option indicates that some TCP rules
must be checked upon accept on this listener. It is now checked by
the frontend and the L4 rules are evaluated only in this case. The
flag is only set when at least one tcp-req rule is present in the
frontend.

The L4 rules check function has now been moved to proto_tcp.c where
it ought to be.

include/proto/proto_tcp.h
include/types/protocols.h
src/cfgparse.c
src/frontend.c
src/proto_tcp.c

index 5c0087b814da035b3520bc456831e3ed58e1ec2f..37d8ea8bd6420d0abd3d8bd1d216091e47c77189 100644 (file)
@@ -35,6 +35,7 @@ int tcpv4_connect_server(struct stream_interface *si,
                         struct sockaddr *srv_addr, struct sockaddr *from_addr);
 int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit);
 int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit);
+int tcp_exec_req_rules(struct session *s);
 
 #endif /* _PROTO_PROTO_TCP_H */
 
index 0911a40e701907e4c0277b2c3c992d6b49f51660..8f8faefbe13d772244e89998ddd507fdab6fd2b7 100644 (file)
@@ -72,6 +72,7 @@
 #define LI_O_FOREIGN   0x0002  /* permit listening on foreing addresses */
 #define LI_O_NOQUICKACK        0x0004  /* disable quick ack of immediate data (linux) */
 #define LI_O_DEF_ACCEPT        0x0008  /* wait up to 1 second for data before accepting */
+#define LI_O_TCP_RULES  0x0010  /* run TCP rules checks on the incoming connection */
 
 /* The listener will be directly referenced by the fdtab[] which holds its
  * socket. The listener provides the protocol-specific accept() function to
index e5b66e8ca2ba9a72094ca0daeddd18bbccbfffee..41313783febced6d156cbe5316eec98b7ec6006e 100644 (file)
@@ -5356,6 +5356,9 @@ out_uri_auth_compat:
                        listener->handler = process_session;
                        listener->analysers |= curproxy->fe_req_ana;
 
+                       if (!LIST_ISEMPTY(&curproxy->tcp_req.l4_rules))
+                               listener->options |= LI_O_TCP_RULES;
+
                        /* smart accept mode is automatic in HTTP mode */
                        if ((curproxy->options2 & PR_O2_SMARTACC) ||
                            (curproxy->mode == PR_MODE_HTTP &&
index 08569ff4fbdbfa66fa9e66f5bfd67ff190970c2d..5af5582e8e46a3afaa5c567a0375027201c835a0 100644 (file)
@@ -63,7 +63,6 @@ int frontend_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
        struct session *s;
        struct http_txn *txn;
        struct task *t;
-       struct tcp_rule *rule;
 
        if (unlikely((s = pool_alloc2(pool2_session)) == NULL)) {
                Alert("out of memory in event_accept().\n");
@@ -134,40 +133,13 @@ int frontend_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
        proxy_inc_fe_ctr(l, p); /* note: cum_beconn will be increased once assigned */
 
        /* now evaluate the tcp-request rules */
-       list_for_each_entry(rule, &p->tcp_req.l4_rules, list) {
-               int ret = ACL_PAT_PASS;
-
-               if (rule->cond) {
-                       ret = acl_exec_cond(rule->cond, p, s, &s->txn, ACL_DIR_REQ);
-                       ret = acl_pass(ret);
-                       if (rule->cond->pol == ACL_COND_UNLESS)
-                               ret = !ret;
-               }
-
-               if (ret) {
-                       /* we have a matching rule. */
-                       if (rule->action == TCP_ACT_REJECT) {
-                               p->counters.denied_req++;
-                               if (l->counters)
-                                       l->counters->denied_req++;
-
-                               if (!(s->flags & SN_ERR_MASK))
-                                       s->flags |= SN_ERR_PRXCOND;
-                               if (!(s->flags & SN_FINST_MASK))
-                                       s->flags |= SN_FINST_R;
-
-                               task_free(t);
-                               LIST_DEL(&s->list);
-                               pool_free2(pool2_session, s);
-
-                               /* let's do a no-linger now to close with a single RST. */
-                               setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
-                               return 0;
-                       }
-
-                       /* otherwise it's an accept */
-                       break;
-               }
+       if ((l->options & LI_O_TCP_RULES) && !tcp_exec_req_rules(s)) {
+               task_free(t);
+               LIST_DEL(&s->list);
+               pool_free2(pool2_session, s);
+               /* let's do a no-linger now to close with a single RST. */
+               setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
+               return 0;
        }
 
        /* pre-initialize the other side's stream interface */
index b753c3bbd483d3a7e12e7ec130e1974d1b479642..3a1abad9e6e12942cbbb4678b923d12c4dafe08f 100644 (file)
@@ -708,6 +708,46 @@ int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit)
        return 1;
 }
 
+/* This function performs the TCP layer4 analysis on the current request. It
+ * returns 0 if a reject rule matches, otherwise 1 if either an accept rule
+ * matches or if no more rule matches. It can only use rules which don't need
+ * any data.
+ */
+int tcp_exec_req_rules(struct session *s)
+{
+       struct tcp_rule *rule;
+       int ret;
+
+       list_for_each_entry(rule, &s->fe->tcp_req.l4_rules, list) {
+               ret = ACL_PAT_PASS;
+
+               if (rule->cond) {
+                       ret = acl_exec_cond(rule->cond, s->fe, s, NULL, ACL_DIR_REQ);
+                       ret = acl_pass(ret);
+                       if (rule->cond->pol == ACL_COND_UNLESS)
+                               ret = !ret;
+               }
+
+               if (ret) {
+                       /* we have a matching rule. */
+                       if (rule->action == TCP_ACT_REJECT) {
+                               s->fe->counters.denied_req++;
+                               if (s->listener->counters)
+                                       s->listener->counters->denied_req++;
+
+                               if (!(s->flags & SN_ERR_MASK))
+                                       s->flags |= SN_ERR_PRXCOND;
+                               if (!(s->flags & SN_FINST_MASK))
+                                       s->flags |= SN_FINST_R;
+                               return 0;
+                       }
+                       /* otherwise it's an accept */
+                       break;
+               }
+       }
+       return 1;
+}
+
 /* This function should be called to parse a line starting with the "tcp-request"
  * keyword.
  */