mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 15:47:01 +02:00
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:
parent
14174bc4c0
commit
c0239e0425
@ -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:
|
||||
|
233
src/proto_http.c
233
src/proto_http.c
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user