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 */
#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
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 &&
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");
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 */
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.
*/