From a434a008648fe430b016b387b001af08aaacd39d Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Thu, 25 Mar 2021 11:58:51 +0100 Subject: [PATCH] BUG/MINOR: payload/htx: Ingore L6 sample fetches for HTX streams/checks Use a L6 sample fetch on an HTX streams or a HTX health-check is meaningless because data are not raw but structured. So now, these sample fetches fail when called from an HTTP proxy. In addition, a warning has been added in the configuration manual, at the begining of the L6 sample fetches section. Note that req.len and res.len samples return the HTX data size instead of failing. It is not accurate because it does not reflect the buffer size nor the raw data length. But we keep it for backward compatibility purpose. However it remains a bit strange to use it on an HTTP proxy. This patch may be backported to all versions supporting the HTX, i.e as far as 2.0. But the part about the health-checks is only valid for the 2.2 and upper. --- doc/configuration.txt | 8 +++++ src/payload.c | 70 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index f5d19f9449..8c33a5ca7e 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -18404,6 +18404,14 @@ sample fetch methods to ensure that the expected data are complete and usable, for example through TCP request content inspection. Please see the "tcp-request content" keyword for more detailed information on the subject. +Warning : Following sample fetches are ignored if used from HTTP proxies. They + only deal with raw contents found in the buffers. On their side, + HTTTP proxies use structured content. Thus raw representation of + these data are meaningless. A warning is emitted if an ACL relies on + one of the following sample fetches. But it is not possible to detect + all invalid usage (for instance inside a log-format string or a + sample expression). So be careful. + payload(,) : binary (deprecated) This is an alias for "req.payload" when used in the context of a request (e.g. "stick on", "stick match"), and for "res.payload" when used in the context of diff --git a/src/payload.c b/src/payload.c index 26994cff1a..32e5456e62 100644 --- a/src/payload.c +++ b/src/payload.c @@ -50,6 +50,8 @@ smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void * { if (smp->strm) { struct channel *chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; + + /* Not accurate but kept for backward compatibility purpose */ if (IS_HTX_STRM(smp->strm)) { struct htx *htx = htxbuf(&chn->buf); smp->data.u.sint = htx->data - co_data(chn); @@ -59,6 +61,8 @@ smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void * } else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) { struct check *check = __objt_check(smp->sess->origin); + + /* Not accurate but kept for backward compatibility purpose */ smp->data.u.sint = ((check->cs && IS_HTX_CS(check->cs)) ? (htxbuf(&check->bi))->data: b_data(&check->bi)); } else @@ -84,7 +88,13 @@ smp_fetch_req_ssl_st_ext(const struct arg *args, struct sample *smp, const char if (!smp->strm) goto not_ssl_hello; + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + goto not_ssl_hello; + chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; + + bleft = ci_data(chn); data = (unsigned char *)ci_head(chn); @@ -214,6 +224,10 @@ smp_fetch_req_ssl_ec_ext(const struct arg *args, struct sample *smp, const char if (!smp->strm) goto not_ssl_hello; + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + goto not_ssl_hello; + chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; bleft = ci_data(chn); data = (unsigned char *)ci_head(chn); @@ -335,6 +349,10 @@ smp_fetch_ssl_hello_type(const struct arg *args, struct sample *smp, const char if (!smp->strm) goto not_ssl_hello; + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + goto not_ssl_hello; + chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; bleft = ci_data(chn); data = (const unsigned char *)ci_head(chn); @@ -399,7 +417,11 @@ smp_fetch_req_ssl_ver(const struct arg *args, struct sample *smp, const char *kw struct channel *req; if (!smp->strm) - return 0; + goto not_ssl; + + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + goto not_ssl; req = &smp->strm->req; msg_len = 0; @@ -541,6 +563,10 @@ smp_fetch_ssl_hello_sni(const struct arg *args, struct sample *smp, const char * if (!smp->strm) goto not_ssl_hello; + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + goto not_ssl_hello; + chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; bleft = ci_data(chn); data = (unsigned char *)ci_head(chn); @@ -707,6 +733,10 @@ smp_fetch_ssl_hello_alpn(const struct arg *args, struct sample *smp, const char if (!smp->strm) goto not_ssl_hello; + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + goto not_ssl_hello; + chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; bleft = ci_data(chn); data = (unsigned char *)ci_head(chn); @@ -933,6 +963,10 @@ smp_fetch_rdp_cookie(const struct arg *args, struct sample *smp, const char *kw, if (!smp->strm) return 0; + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + return 0; + return fetch_rdp_cookie_name(smp->strm, smp, args ? args->data.str.area : NULL, args ? args->data.str.data : 0); @@ -973,14 +1007,21 @@ smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */ if (smp->strm) { + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + return 0; chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; head = ci_head(chn); data = ci_data(chn); } else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) { - struct buffer *buf = &(__objt_check(smp->sess->origin)->bi); - head = b_head(buf); - data = b_data(buf); + struct check *check = __objt_check(smp->sess->origin); + + /* meaningless for HTX buffers */ + if (check->cs && IS_HTX_CS(check->cs)) + return 0; + head = b_head(&check->bi); + data = b_data(&check->bi); } max = global.tune.bufsize; if (!head) @@ -1035,14 +1076,21 @@ smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, v size_t max, data; if (smp->strm) { + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + return 0; chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; head = ci_head(chn); data = ci_data(chn); } else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) { - struct buffer *buf = &(__objt_check(smp->sess->origin)->bi); - head = b_head(buf); - data = b_data(buf); + struct check *check = __objt_check(smp->sess->origin); + + /* meaningless for HTX buffers */ + if (check->cs && IS_HTX_CS(check->cs)) + return 0; + head = b_head(&check->bi); + data = b_data(&check->bi); } max = global.tune.bufsize; if (!head) @@ -1143,6 +1191,10 @@ smp_fetch_distcc_param(const struct arg *arg_p, struct sample *smp, const char * if (!smp->strm) return 0; + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + return 0; + chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; ofs = 0; occ = 0; @@ -1220,6 +1272,10 @@ smp_fetch_distcc_body(const struct arg *arg_p, struct sample *smp, const char *k if (!smp->strm) return 0; + /* meaningless for HTX buffers */ + if (IS_HTX_STRM(smp->strm)) + return 0; + chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; ofs = 0; occ = 0;