- BUG/MINOR: ssl: Fix external function in order not to return a pointer on an internal trash buffer - BUG/MINOR: counters: do not untrack counters before logging - BUG/MAJOR: sample: correctly reinitialize sample fetch context before calling sample_process() - MINOR: stick-table: make stktable_fetch_key() indicate why it failed - BUG/MEDIUM: counters: fix track-sc* to wait on unstable contents Signed-off-by: Thomas Heil <heil@terminal-consulting.de>lilik-openwrt-22.03
@ -0,0 +1,101 @@ | |||||
From 4910098653e356f814924663b4ddf71c971a71d6 Mon Sep 17 00:00:00 2001 | |||||
From: Emeric Brun <ebrun@haproxy.com> | |||||
Date: Tue, 24 Jun 2014 18:26:41 +0200 | |||||
Subject: [PATCH 2/6] BUG/MINOR: ssl: Fix external function in order not to | |||||
return a pointer on an internal trash buffer. | |||||
'ssl_sock_get_common_name' applied to a connection was also renamed | |||||
'ssl_sock_get_remote_common_name'. Currently, this function is only used | |||||
with protocol PROXYv2 to retrieve the client certificate's common name. | |||||
A further usage could be to retrieve the server certificate's common name | |||||
on an outgoing connection. | |||||
(cherry picked from commit 0abf836ecb32767fa1f9ad598f3e236e073491bd) | |||||
--- | |||||
include/proto/ssl_sock.h | 2 +- | |||||
src/connection.c | 5 ++--- | |||||
src/ssl_sock.c | 23 +++++++++++------------ | |||||
3 files changed, 14 insertions(+), 16 deletions(-) | |||||
diff --git a/include/proto/ssl_sock.h b/include/proto/ssl_sock.h | |||||
index 0902fde..3e111cd 100644 | |||||
--- a/include/proto/ssl_sock.h | |||||
+++ b/include/proto/ssl_sock.h | |||||
@@ -52,7 +52,7 @@ const char *ssl_sock_get_cipher_name(struct connection *conn); | |||||
const char *ssl_sock_get_proto_version(struct connection *conn); | |||||
char *ssl_sock_get_version(struct connection *conn); | |||||
int ssl_sock_get_cert_used(struct connection *conn); | |||||
-char *ssl_sock_get_common_name(struct connection *conn); | |||||
+int ssl_sock_get_remote_common_name(struct connection *conn, struct chunk *out); | |||||
unsigned int ssl_sock_get_verify_result(struct connection *conn); | |||||
#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB | |||||
int ssl_sock_update_ocsp_response(struct chunk *ocsp_response, char **err); | |||||
diff --git a/src/connection.c b/src/connection.c | |||||
index 0b154d8..20a911b 100644 | |||||
--- a/src/connection.c | |||||
+++ b/src/connection.c | |||||
@@ -682,9 +682,8 @@ int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connec | |||||
tlv->verify = htonl(ssl_sock_get_verify_result(remote)); | |||||
} | |||||
if (srv->pp_opts & SRV_PP_V2_SSL_CN) { | |||||
- value = ssl_sock_get_common_name(remote); | |||||
- if (value) { | |||||
- tlv_len = make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_TYPE_SSL_CN, strlen(value), value); | |||||
+ if (ssl_sock_get_remote_common_name(remote, &trash) > 0) { | |||||
+ tlv_len = make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_TYPE_SSL_CN, trash.len, trash.str); | |||||
ssl_tlv_len += tlv_len; | |||||
} | |||||
} | |||||
diff --git a/src/ssl_sock.c b/src/ssl_sock.c | |||||
index 328b978..375225d 100644 | |||||
--- a/src/ssl_sock.c | |||||
+++ b/src/ssl_sock.c | |||||
@@ -2654,21 +2654,25 @@ char *ssl_sock_get_version(struct connection *conn) | |||||
return (char *)SSL_get_version(conn->xprt_ctx); | |||||
} | |||||
-/* returns common name, NULL terminated, from client certificate, or NULL if none */ | |||||
-char *ssl_sock_get_common_name(struct connection *conn) | |||||
+/* Extract peer certificate's common name into the chunk dest | |||||
+ * Returns | |||||
+ * the len of the extracted common name | |||||
+ * or 0 if no CN found in DN | |||||
+ * or -1 on error case (i.e. no peer certificate) | |||||
+ */ | |||||
+int ssl_sock_get_remote_common_name(struct connection *conn, struct chunk *dest) | |||||
{ | |||||
X509 *crt = NULL; | |||||
X509_NAME *name; | |||||
- struct chunk *cn_trash; | |||||
const char find_cn[] = "CN"; | |||||
const struct chunk find_cn_chunk = { | |||||
.str = (char *)&find_cn, | |||||
.len = sizeof(find_cn)-1 | |||||
}; | |||||
- char *result = NULL; | |||||
+ int result = -1; | |||||
if (!ssl_sock_is_ssl(conn)) | |||||
- return NULL; | |||||
+ goto out; | |||||
/* SSL_get_peer_certificate, it increase X509 * ref count */ | |||||
crt = SSL_get_peer_certificate(conn->xprt_ctx); | |||||
@@ -2679,13 +2683,8 @@ char *ssl_sock_get_common_name(struct connection *conn) | |||||
if (!name) | |||||
goto out; | |||||
- cn_trash = get_trash_chunk(); | |||||
- if (ssl_sock_get_dn_entry(name, &find_cn_chunk, 1, cn_trash) <= 0) | |||||
- goto out; | |||||
- cn_trash->str[cn_trash->len] = '\0'; | |||||
- result = cn_trash->str; | |||||
- | |||||
- out: | |||||
+ result = ssl_sock_get_dn_entry(name, &find_cn_chunk, 1, dest); | |||||
+out: | |||||
if (crt) | |||||
X509_free(crt); | |||||
-- | |||||
1.8.5.5 | |||||
@ -0,0 +1,42 @@ | |||||
From c177ea7187bc1918a1900c1b0e3fc67c559987a2 Mon Sep 17 00:00:00 2001 | |||||
From: Willy Tarreau <w@1wt.eu> | |||||
Date: Wed, 25 Jun 2014 15:36:04 +0200 | |||||
Subject: [PATCH 3/6] BUG/MINOR: counters: do not untrack counters before | |||||
logging | |||||
Baptiste Assmann reported a corner case in the releasing of stick-counters: | |||||
we release content-aware counters before logging. In the past it was not a | |||||
problem, but since now we can log them it, it prevents one from logging | |||||
their value. Simply switching the log production and the release of the | |||||
counter fixes the issue. | |||||
This should be backported into 1.5. | |||||
(cherry picked from commit d713bcc326da5d1ac80adab666d7710f3e37650c) | |||||
--- | |||||
src/proto_http.c | 3 ++- | |||||
1 file changed, 2 insertions(+), 1 deletion(-) | |||||
diff --git a/src/proto_http.c b/src/proto_http.c | |||||
index 5321f7d..d566bcc 100644 | |||||
--- a/src/proto_http.c | |||||
+++ b/src/proto_http.c | |||||
@@ -4808,7 +4808,6 @@ void http_end_txn_clean_session(struct session *s) | |||||
s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now); | |||||
session_process_counters(s); | |||||
- session_stop_content_counters(s); | |||||
if (s->txn.status) { | |||||
int n; | |||||
@@ -4842,6 +4841,8 @@ void http_end_txn_clean_session(struct session *s) | |||||
s->do_log(s); | |||||
} | |||||
+ /* stop tracking content-based counters */ | |||||
+ session_stop_content_counters(s); | |||||
session_update_time_stats(s); | |||||
s->logs.accept_date = date; /* user-visible date for logging */ | |||||
-- | |||||
1.8.5.5 | |||||
@ -0,0 +1,65 @@ | |||||
From a4ba9dbfc688576ffb7e0a3ce43ac0b420211bf6 Mon Sep 17 00:00:00 2001 | |||||
From: Willy Tarreau <w@1wt.eu> | |||||
Date: Wed, 25 Jun 2014 16:56:41 +0200 | |||||
Subject: [PATCH 4/6] BUG/MAJOR: sample: correctly reinitialize sample fetch | |||||
context before calling sample_process() | |||||
We used to only clear flags when reusing the static sample before calling | |||||
sample_process(), but that's not enough because there's a context in samples | |||||
that can be used by some fetch functions such as auth, headers and cookies, | |||||
and not reinitializing it risks that a pointer of a different type is used | |||||
in the wrong context. | |||||
An example configuration which triggers the case consists in mixing hdr() | |||||
and http_auth_group() which both make use of contexts : | |||||
http-request add-header foo2 %[hdr(host)],%[http_auth_group(foo)] | |||||
The solution is simple, initialize all the sample and not just the flags. | |||||
This fix must be backported into 1.5 since it was introduced in 1.5-dev19. | |||||
(cherry picked from commit 6c616e0b96106dd33d183afbda31e72799e967c3) | |||||
--- | |||||
src/proto_http.c | 3 +++ | |||||
src/sample.c | 5 +++-- | |||||
2 files changed, 6 insertions(+), 2 deletions(-) | |||||
diff --git a/src/proto_http.c b/src/proto_http.c | |||||
index d566bcc..01fe62d 100644 | |||||
--- a/src/proto_http.c | |||||
+++ b/src/proto_http.c | |||||
@@ -9748,6 +9748,9 @@ smp_prefetch_http(struct proxy *px, struct session *s, void *l7, unsigned int op | |||||
return 1; | |||||
} | |||||
+/* Note: these functinos *do* modify the sample. Even in case of success, at | |||||
+ * least the type and uint value are modified. | |||||
+ */ | |||||
#define CHECK_HTTP_MESSAGE_FIRST() \ | |||||
do { int r = smp_prefetch_http(px, l4, l7, opt, args, smp, 1); if (r <= 0) return r; } while (0) | |||||
diff --git a/src/sample.c b/src/sample.c | |||||
index 9f22ef9..3a0f3fb 100644 | |||||
--- a/src/sample.c | |||||
+++ b/src/sample.c | |||||
@@ -905,7 +905,7 @@ struct sample *sample_process(struct proxy *px, struct session *l4, void *l7, | |||||
if (p == NULL) { | |||||
p = &temp_smp; | |||||
- p->flags = 0; | |||||
+ memset(p, 0, sizeof(*p)); | |||||
} | |||||
if (!expr->fetch->process(px, l4, l7, opt, expr->arg_p, p, expr->fetch->kw)) | |||||
@@ -1160,7 +1160,8 @@ struct sample *sample_fetch_string(struct proxy *px, struct session *l4, void *l | |||||
{ | |||||
struct sample *smp = &temp_smp; | |||||
- smp->flags = 0; | |||||
+ memset(smp, 0, sizeof(*smp)); | |||||
+ | |||||
if (!sample_process(px, l4, l7, opt, expr, smp)) { | |||||
if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL)) | |||||
return smp; | |||||
-- | |||||
1.8.5.5 | |||||
@ -0,0 +1,109 @@ | |||||
From d008394057c4fe46ca6eb775c66cc0ff986a5495 Mon Sep 17 00:00:00 2001 | |||||
From: Willy Tarreau <w@1wt.eu> | |||||
Date: Wed, 25 Jun 2014 16:20:53 +0200 | |||||
Subject: [PATCH 5/6] MINOR: stick-table: make stktable_fetch_key() indicate | |||||
why it failed | |||||
stktable_fetch_key() does not indicate whether it returns NULL because | |||||
the input sample was not found or because it's unstable. It causes trouble | |||||
with track-sc* rules. Just like with sample_fetch_string(), we want it to | |||||
be able to give more information to the caller about what it found. Thus, | |||||
now we use the pointer to a sample passed by the caller, and fill it with | |||||
the information we have about the sample. That way, even if we return NULL, | |||||
the caller has the ability to check whether a sample was found and if it is | |||||
still changing or not. | |||||
(cherry picked from commit b5975defba61e7ef37ae771614166d0970ede04e) | |||||
--- | |||||
include/proto/stick_table.h | 2 +- | |||||
src/proto_tcp.c | 4 ++-- | |||||
src/session.c | 4 ++-- | |||||
src/stick_table.c | 12 +++++++----- | |||||
4 files changed, 12 insertions(+), 10 deletions(-) | |||||
diff --git a/include/proto/stick_table.h b/include/proto/stick_table.h | |||||
index 0c26fbe..57ca223 100644 | |||||
--- a/include/proto/stick_table.h | |||||
+++ b/include/proto/stick_table.h | |||||
@@ -48,7 +48,7 @@ struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key | |||||
struct stksess *stktable_update_key(struct stktable *table, struct stktable_key *key); | |||||
struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, | |||||
struct session *l4, void *l7, unsigned int opt, | |||||
- struct sample_expr *expr); | |||||
+ struct sample_expr *expr, struct sample *smp); | |||||
int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type); | |||||
int stktable_get_data_type(char *name); | |||||
struct proxy *find_stktable(const char *name); | |||||
diff --git a/src/proto_tcp.c b/src/proto_tcp.c | |||||
index 65c4fda..1aac0d9 100644 | |||||
--- a/src/proto_tcp.c | |||||
+++ b/src/proto_tcp.c | |||||
@@ -1027,7 +1027,7 @@ int tcp_inspect_request(struct session *s, struct channel *req, int an_bit) | |||||
continue; | |||||
t = rule->act_prm.trk_ctr.table.t; | |||||
- key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr); | |||||
+ key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr, NULL); | |||||
if (key && (ts = stktable_get_entry(t, key))) { | |||||
session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts); | |||||
@@ -1228,7 +1228,7 @@ int tcp_exec_req_rules(struct session *s) | |||||
continue; | |||||
t = rule->act_prm.trk_ctr.table.t; | |||||
- key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr); | |||||
+ key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr, NULL); | |||||
if (key && (ts = stktable_get_entry(t, key))) | |||||
session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts); | |||||
diff --git a/src/session.c b/src/session.c | |||||
index e26f5ad..df85170 100644 | |||||
--- a/src/session.c | |||||
+++ b/src/session.c | |||||
@@ -1458,7 +1458,7 @@ static int process_sticking_rules(struct session *s, struct channel *req, int an | |||||
if (ret) { | |||||
struct stktable_key *key; | |||||
- key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->expr); | |||||
+ key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->expr, NULL); | |||||
if (!key) | |||||
continue; | |||||
@@ -1561,7 +1561,7 @@ static int process_store_rules(struct session *s, struct channel *rep, int an_bi | |||||
if (ret) { | |||||
struct stktable_key *key; | |||||
- key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL, rule->expr); | |||||
+ key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL, rule->expr, NULL); | |||||
if (!key) | |||||
continue; | |||||
diff --git a/src/stick_table.c b/src/stick_table.c | |||||
index c6463ec..a708d3c 100644 | |||||
--- a/src/stick_table.c | |||||
+++ b/src/stick_table.c | |||||
@@ -601,15 +601,17 @@ static sample_to_key_fct sample_to_key[SMP_TYPES][STKTABLE_TYPES] = { | |||||
* Process a fetch + format conversion as defined by the sample expression <expr> | |||||
* on request or response considering the <opt> parameter. Returns either NULL if | |||||
* no key could be extracted, or a pointer to the converted result stored in | |||||
- * static_table_key in format <table_type>. | |||||
+ * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset | |||||
+ * and its flags will be initialized so that the caller gets a copy of the input | |||||
+ * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present). | |||||
*/ | |||||
struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *l4, void *l7, | |||||
- unsigned int opt, | |||||
- struct sample_expr *expr) | |||||
+ unsigned int opt, struct sample_expr *expr, struct sample *smp) | |||||
{ | |||||
- struct sample *smp; | |||||
+ if (smp) | |||||
+ memset(smp, 0, sizeof(*smp)); | |||||
- smp = sample_process(px, l4, l7, opt, expr, NULL); | |||||
+ smp = sample_process(px, l4, l7, opt, expr, smp); | |||||
if (!smp) | |||||
return NULL; | |||||
-- | |||||
1.8.5.5 | |||||
@ -0,0 +1,57 @@ | |||||
From 86bd33a9f842caf1788b61d1f99e95f8ad866660 Mon Sep 17 00:00:00 2001 | |||||
From: Willy Tarreau <w@1wt.eu> | |||||
Date: Wed, 25 Jun 2014 17:01:56 +0200 | |||||
Subject: [PATCH 6/6] BUG/MEDIUM: counters: fix track-sc* to wait on unstable | |||||
contents | |||||
I've been facing multiple configurations which involved track-sc* rules | |||||
in tcp-request content without the "if ..." to force it to wait for the | |||||
contents, resulting in random behaviour with contents sometimes retrieved | |||||
and sometimes not. | |||||
Reading the doc doesn't make it clear either that the tracking will be | |||||
performed only if data are already there and that waiting on an ACL is | |||||
the only way to avoid this. | |||||
Since this behaviour is not natural and we now have the ability to fix | |||||
it, this patch ensures that if input data are still moving, instead of | |||||
silently dropping them, we naturally wait for them to stabilize up to | |||||
the inspect-delay. This way it's not needed anymore to implement an | |||||
ACL-based condition to force to wait for data, eventhough the behaviour | |||||
is not changed for when an ACL is present. | |||||
The most obvious usage will be when track-sc is followed by any HTTP | |||||
sample expression, there's no need anymore for adding "if HTTP". | |||||
It's probably worth backporting this to 1.5 to avoid further configuration | |||||
issues. Note that it requires previous patch. | |||||
(cherry picked from commit 1b71eb581ec1637879f725421efb95ad69f0ea4f) | |||||
--- | |||||
src/proto_tcp.c | 6 +++++- | |||||
1 file changed, 5 insertions(+), 1 deletion(-) | |||||
diff --git a/src/proto_tcp.c b/src/proto_tcp.c | |||||
index 1aac0d9..e9dbc9c 100644 | |||||
--- a/src/proto_tcp.c | |||||
+++ b/src/proto_tcp.c | |||||
@@ -1022,12 +1022,16 @@ int tcp_inspect_request(struct session *s, struct channel *req, int an_bit) | |||||
* applies. | |||||
*/ | |||||
struct stktable_key *key; | |||||
+ struct sample smp; | |||||
if (stkctr_entry(&s->stkctr[tcp_trk_idx(rule->action)])) | |||||
continue; | |||||
t = rule->act_prm.trk_ctr.table.t; | |||||
- key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr, NULL); | |||||
+ key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial, rule->act_prm.trk_ctr.expr, &smp); | |||||
+ | |||||
+ if (smp.flags & SMP_F_MAY_CHANGE) | |||||
+ goto missing_data; | |||||
if (key && (ts = stktable_get_entry(t, key))) { | |||||
session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts); | |||||
-- | |||||
1.8.5.5 | |||||