haproxy: patches from upstream (ssl,counter,stick-table, track)
authorThomas Heil <heil@terminal-consulting.de>
Thu, 26 Jun 2014 04:22:41 +0000 (06:22 +0200)
committerThomas Heil <heil@terminal-consulting.de>
Thu, 26 Jun 2014 04:22:41 +0000 (06:22 +0200)
 - 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>
net/haproxy/Makefile
net/haproxy/patches/0002-BUG-MINOR-ssl-Fix-external-function-in-order-not-to-.patch [new file with mode: 0644]
net/haproxy/patches/0003-BUG-MINOR-counters-do-not-untrack-counters-before-lo.patch [new file with mode: 0644]
net/haproxy/patches/0004-BUG-MAJOR-sample-correctly-reinitialize-sample-fetch.patch [new file with mode: 0644]
net/haproxy/patches/0005-MINOR-stick-table-make-stktable_fetch_key-indicate-w.patch [new file with mode: 0644]
net/haproxy/patches/0006-BUG-MEDIUM-counters-fix-track-sc-to-wait-on-unstable.patch [new file with mode: 0644]

index 2f46115700cd7086d2a09559c6f9e4dd0ae594a3..3fe090716d08840d3d4701267ed8e225347a0233 100644 (file)
@@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=haproxy
 PKG_VERSION:=1.5.1
-PKG_RELEASE:=01
+PKG_RELEASE:=06
 PKG_SOURCE:=haproxy-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=http://haproxy.1wt.eu/download/1.5/src/
 PKG_MD5SUM:=49640cf3ddd793a05fbd3394481a1ed4
diff --git a/net/haproxy/patches/0002-BUG-MINOR-ssl-Fix-external-function-in-order-not-to-.patch b/net/haproxy/patches/0002-BUG-MINOR-ssl-Fix-external-function-in-order-not-to-.patch
new file mode 100644 (file)
index 0000000..0bb82ec
--- /dev/null
@@ -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
+
diff --git a/net/haproxy/patches/0003-BUG-MINOR-counters-do-not-untrack-counters-before-lo.patch b/net/haproxy/patches/0003-BUG-MINOR-counters-do-not-untrack-counters-before-lo.patch
new file mode 100644 (file)
index 0000000..2330eb1
--- /dev/null
@@ -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
+
diff --git a/net/haproxy/patches/0004-BUG-MAJOR-sample-correctly-reinitialize-sample-fetch.patch b/net/haproxy/patches/0004-BUG-MAJOR-sample-correctly-reinitialize-sample-fetch.patch
new file mode 100644 (file)
index 0000000..a145cce
--- /dev/null
@@ -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
+
diff --git a/net/haproxy/patches/0005-MINOR-stick-table-make-stktable_fetch_key-indicate-w.patch b/net/haproxy/patches/0005-MINOR-stick-table-make-stktable_fetch_key-indicate-w.patch
new file mode 100644 (file)
index 0000000..f93601a
--- /dev/null
@@ -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
+
diff --git a/net/haproxy/patches/0006-BUG-MEDIUM-counters-fix-track-sc-to-wait-on-unstable.patch b/net/haproxy/patches/0006-BUG-MEDIUM-counters-fix-track-sc-to-wait-on-unstable.patch
new file mode 100644 (file)
index 0000000..2bfe2de
--- /dev/null
@@ -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
+