MEDIUM: http: make all ACL fetch function use acl_prefetch_http()

All ACLs which need to process HTTP contents first call this function which
performs all the preliminary tests and also triggers the request parsing if
needed. A macro was written to simplify the code.

As a side effect, it's not required anymore to check for the HTTP ACL before
checking for HTTP contents.
This commit is contained in:
Willy Tarreau 2012-04-16 14:42:55 +02:00
parent 14174bc4c0
commit c0239e0425
2 changed files with 36 additions and 208 deletions

View File

@ -6119,17 +6119,18 @@ tcp-request content <action> [{if | unless} <condition>]
"track-sc*" actions as well as for changing the default action to a reject.
It is perfectly possible to match layer 7 contents with "tcp-request content"
rules, but then it is important to ensure that a full request has been
buffered, otherwise no contents will match. In order to achieve this, the
best solution involves detecting the HTTP protocol during the inspection
period.
rules, since HTTP-specific ACL matches are able to preliminarily parse the
contents of a buffer before extracting the required data. If the buffered
contents do not parse as a valid HTTP message, then the ACL does not match.
The parser which is involved there is exactly the same as for all other HTTP
processing, so there is no risk of parsing something differently.
Example:
# Accept HTTP requests containing a Host header saying "example.com"
# and reject everything else.
acl is_host_com hdr(Host) -i example.com
tcp-request inspect-delay 30s
tcp-request content accept if HTTP is_host_com
tcp-request content accept if is_host_com
tcp-request content reject
Example:

View File

@ -7610,6 +7610,9 @@ acl_prefetch_http(struct proxy *px, struct session *s, void *l7, int dir,
return 1;
}
#define CHECK_HTTP_MESSAGE_FIRST() \
do { int r = acl_prefetch_http(px, l4, l7, dir, expr, test); if (r <= 0) return r; } while (0)
/* 1. Check on METHOD
* We use the pre-parsed method if it is known, and store its number as an
@ -7647,11 +7650,7 @@ acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
int meth;
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
meth = txn->meth;
temp_pattern.data.str.len = meth;
@ -7715,11 +7714,7 @@ acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
char *ptr;
int len;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
len = txn->req.sl.rq.v_l;
ptr = txn->req.buf->p + txn->req.sol + txn->req.sl.rq.v;
@ -7743,11 +7738,7 @@ acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
char *ptr;
int len;
if (!txn)
return 0;
if (txn->rsp.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
len = txn->rsp.sl.st.v_l;
ptr = txn->rsp.buf->p + txn->rsp.sol;
@ -7772,11 +7763,7 @@ acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
char *ptr;
int len;
if (!txn)
return 0;
if (txn->rsp.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
len = txn->rsp.sl.st.c_l;
ptr = txn->rsp.buf->p + txn->rsp.sol + txn->rsp.sl.st.c;
@ -7793,15 +7780,7 @@ acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
temp_pattern.data.str.len = txn->req.sl.rq.u_l;
temp_pattern.data.str.str = txn->req.buf->p + txn->req.sol + txn->req.sl.rq.u;
@ -7817,15 +7796,7 @@ acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
/* Parse HTTP request */
url2sa(txn->req.buf->p + txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->req->cons->addr.to);
@ -7851,15 +7822,7 @@ acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
/* Same optimization as url_ip */
url2sa(txn->req.buf->p + txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->req->cons->addr.to);
@ -7883,9 +7846,6 @@ acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
struct hdr_idx *idx = &txn->hdr_idx;
struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
if (!txn)
return 0;
if (!(test->flags & ACL_TEST_F_FETCH_MORE))
/* search for header from the beginning */
ctx->idx = 0;
@ -7910,15 +7870,7 @@ acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
return acl_fetch_hdr(px, l4, txn, txn->req.buf->p + txn->req.sol, expr, test);
}
@ -7929,11 +7881,7 @@ acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->rsp.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
return acl_fetch_hdr(px, l4, txn, txn->rsp.buf->p + txn->rsp.sol, expr, test);
}
@ -7950,9 +7898,6 @@ acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
struct hdr_ctx ctx;
int cnt;
if (!txn)
return 0;
ctx.idx = 0;
cnt = 0;
while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
@ -7969,15 +7914,7 @@ acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
return acl_fetch_hdr_cnt(px, l4, txn, txn->req.buf->p + txn->req.sol, expr, test);
}
@ -7988,11 +7925,7 @@ acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->rsp.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.buf->p + txn->rsp.sol, expr, test);
}
@ -8009,9 +7942,6 @@ acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
struct hdr_idx *idx = &txn->hdr_idx;
struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
if (!txn)
return 0;
if (!(test->flags & ACL_TEST_F_FETCH_MORE))
/* search for header from the beginning */
ctx->idx = 0;
@ -8034,15 +7964,7 @@ acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
return acl_fetch_hdr_val(px, l4, txn, txn->req.buf->p + txn->req.sol, expr, test);
}
@ -8053,11 +7975,7 @@ acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->rsp.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
return acl_fetch_hdr_val(px, l4, txn, txn->rsp.buf->p + txn->rsp.sol, expr, test);
}
@ -8073,9 +7991,6 @@ acl_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, char *sol,
struct hdr_idx *idx = &txn->hdr_idx;
struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
if (!txn)
return 0;
if (!(test->flags & ACL_TEST_F_FETCH_MORE))
/* search for header from the beginning */
ctx->idx = 0;
@ -8101,15 +8016,7 @@ acl_fetch_chdr_ip(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
return acl_fetch_hdr_ip(px, l4, txn, txn->req.buf->p + txn->req.sol, expr, test);
}
@ -8120,11 +8027,7 @@ acl_fetch_shdr_ip(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->rsp.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
return acl_fetch_hdr_ip(px, l4, txn, txn->rsp.buf->p + txn->rsp.sol, expr, test);
}
@ -8139,15 +8042,7 @@ acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
struct http_txn *txn = l7;
char *ptr, *end;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
end = txn->req.buf->p + txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
ptr = http_get_path(txn);
@ -8168,51 +8063,14 @@ acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
}
static int
acl_fetch_proto_http(struct proxy *px, struct session *s, void *l7, int dir,
acl_fetch_proto_http(struct proxy *px, struct session *l4, void *l7, int dir,
struct acl_expr *expr, struct acl_test *test)
{
struct buffer *req = s->req;
struct http_txn *txn = &s->txn;
struct http_msg *msg = &txn->req;
/* Note: hdr_idx.v cannot be NULL in this ACL because the ACL is tagged
* as a layer7 ACL, which involves automatic allocation of hdr_idx.
*/
if (!s || !req)
return 0;
if (unlikely(msg->msg_state >= HTTP_MSG_BODY)) {
/* Already decoded as OK */
test->flags |= ACL_TEST_F_SET_RES_PASS;
return 1;
}
/* Try to decode HTTP request */
if (likely(msg->next < req->i))
http_msg_analyzer(msg, &txn->hdr_idx);
if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
if ((msg->msg_state == HTTP_MSG_ERROR) || (req->flags & BF_FULL)) {
test->flags |= ACL_TEST_F_SET_RES_FAIL;
return 1;
}
/* wait for final state */
test->flags |= ACL_TEST_F_MAY_CHANGE;
return 0;
}
/* OK we got a valid HTTP request. We have some minor preparation to
* perform so that further checks can rely on HTTP tests.
*/
txn->meth = find_http_meth(msg->buf->p + msg->sol, msg->sl.rq.m_l);
if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
s->flags |= SN_REDIRECTABLE;
if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(txn)) {
test->flags |= ACL_TEST_F_SET_RES_FAIL;
return 1;
}
CHECK_HTTP_MESSAGE_FIRST();
test->flags |= ACL_TEST_F_SET_RES_PASS;
return 1;
@ -8235,19 +8093,18 @@ acl_fetch_http_first_req(struct proxy *px, struct session *s, void *l7, int dir,
}
static int
acl_fetch_http_auth(struct proxy *px, struct session *s, void *l7, int dir,
acl_fetch_http_auth(struct proxy *px, struct session *l4, void *l7, int dir,
struct acl_expr *expr, struct acl_test *test)
{
if (!s)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
if (!get_http_auth(s))
if (!get_http_auth(l4))
return 0;
test->ctx.a[0] = expr->arg.ul;
test->ctx.a[1] = s->txn.auth.user;
test->ctx.a[2] = s->txn.auth.pass;
test->ctx.a[1] = l4->txn.auth.user;
test->ctx.a[2] = l4->txn.auth.pass;
test->flags |= ACL_TEST_F_READ_ONLY | ACL_TEST_F_NULL_MATCH;
@ -8364,9 +8221,6 @@ acl_fetch_any_cookie_value(struct proxy *px, struct session *l4, void *l7, char
struct hdr_idx *idx = &txn->hdr_idx;
struct hdr_ctx *ctx = (struct hdr_ctx *)&test->ctx.a[2];
if (!txn)
return 0;
if (!(test->flags & ACL_TEST_F_FETCH_MORE)) {
/* search for the header from the beginning, we must first initialize
* the search parameters.
@ -8412,15 +8266,7 @@ acl_fetch_cookie_value(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
/* The Cookie header allows multiple cookies on the same line */
return acl_fetch_any_cookie_value(px, l4, txn, txn->req.buf->p + txn->req.sol, "Cookie", 6, 1, expr, test);
@ -8432,11 +8278,7 @@ acl_fetch_scookie_value(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->rsp.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
/* The Set-Cookie header allows only one cookie on the same line */
return acl_fetch_any_cookie_value(px, l4, txn, txn->rsp.buf->p + txn->rsp.sol, "Set-Cookie", 10, 0, expr, test);
@ -8457,9 +8299,6 @@ acl_fetch_any_cookie_cnt(struct proxy *px, struct session *l4, void *l7, char *s
int cnt;
char *val_beg, *val_end;
if (!txn)
return 0;
val_end = val_beg = NULL;
ctx.idx = 0;
cnt = 0;
@ -8496,15 +8335,7 @@ acl_fetch_cookie_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->req.msg_state < HTTP_MSG_BODY)
return 0;
if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
/* ensure the indexes are not affected */
return 0;
CHECK_HTTP_MESSAGE_FIRST();
/* The Cookie header allows multiple cookies on the same line */
return acl_fetch_any_cookie_cnt(px, l4, txn, txn->req.buf->p + txn->req.sol, "Cookie", 6, 1, expr, test);
@ -8516,11 +8347,7 @@ acl_fetch_scookie_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
{
struct http_txn *txn = l7;
if (!txn)
return 0;
if (txn->rsp.msg_state < HTTP_MSG_BODY)
return 0;
CHECK_HTTP_MESSAGE_FIRST();
/* The Set-Cookie header allows only one cookie on the same line */
return acl_fetch_any_cookie_cnt(px, l4, txn, txn->rsp.buf->p + txn->rsp.sol, "Set-Cookie", 10, 0, expr, test);