haproxy: add patches from upstream

- [PATCH 1/2] BUG/MEDIUM: stats: properly initialize the scope before
 - [PATCH 2/2] BUG/MEDIUM: http: don't forward client shutdown without
 - [PATCH 3/8] BUG/MINOR: check: fix tcpcheck error message
 - [PATCH 4/8] CLEANUP: checks: fix double usage of cur / current_step
 - [PATCH 5/8] BUG/MEDIUM: checks: do not dereference head of a
 - [PATCH 6/8] CLEANUP: checks: simplify the loop processing of
 - [PATCH 7/8] BUG/MAJOR: checks: always check for end of list before
 - [PATCH 8/8] BUG/MEDIUM: checks: do not dereference a list as a
 - [PATCH 09/10] BUG/MEDIUM: peers: apply a random reconnection timeout
 - [PATCH 10/10] DOC: Update doc about weight, act and bck fields in the
 - [PATCH 11/14] MINOR: ssl: add a destructor to free allocated SSL
 - [PATCH 12/14] BUG/MEDIUM: ssl: fix tune.ssl.default-dh-param value
 - [PATCH 13/14] BUG/MINOR: cfgparse: fix typo in 'option httplog' error
 - [PATCH 14/14] BUG/MEDIUM: cfgparse: segfault when userlist is misused

Signed-off-by: heil <heil@terminal-consulting.de>
This commit is contained in:
heil 2015-06-11 19:03:14 +02:00
parent f109732f56
commit 30908edc95
15 changed files with 1004 additions and 1 deletions

View File

@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=haproxy
PKG_VERSION:=1.5.12
PKG_RELEASE:=01
PKG_RELEASE:=14
PKG_SOURCE:=haproxy-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=http://haproxy.1wt.eu/download/1.5/src/
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)

View File

@ -0,0 +1,32 @@
From 0aa5899911bbc765ba16ce52a80fa76230781779 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Mon, 4 May 2015 18:07:56 +0200
Subject: [PATCH 1/2] BUG/MEDIUM: stats: properly initialize the scope before
dumping stats
Issuing a "show sess all" prior to a "show stat" on the CLI results in no
proxy being dumped because the scope_len union member was not properly
reinitialized.
This fix must be backported into 1.5.
(cherry picked from commit 6bcb95da5b9cb143088102b460c7bcb37c1b3d81)
---
src/dumpstats.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/dumpstats.c b/src/dumpstats.c
index b616478..ca084ac 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -1109,6 +1109,8 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
arg++;
}
+ appctx->ctx.stats.scope_str = 0;
+ appctx->ctx.stats.scope_len = 0;
appctx->ctx.stats.flags = 0;
if (strcmp(args[0], "show") == 0) {
if (strcmp(args[1], "stat") == 0) {
--
2.0.5

View File

@ -0,0 +1,82 @@
From 294e4676a3b775a7accb50eb8428f293c218b5e2 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Mon, 11 May 2015 18:30:33 +0200
Subject: [PATCH 2/2] BUG/MEDIUM: http: don't forward client shutdown without
NOLINGER except for tunnels
There's an issue related with shutting down POST transfers or closing the
connection after the end of the upload : the shutdown is forwarded to the
server regardless of the abortonclose option. The problem it causes is that
during a scan, brute force or whatever, it becomes possible that all source
ports are exhausted with all sockets in TIME_WAIT state.
There are multiple issues at once in fact :
- no action is done for the close, it automatically happens at the lower
layers thanks for channel_auto_close(), so we cannot act on NOLINGER ;
- we *do* want to continue to send a clean shutdown in tunnel mode because
some protocols transported over HTTP may need this, regardless of option
abortonclose, thus we can't set the option inconditionally
- for all other modes, we do want to close the dirty way because we're
certain whether we've sent everything or not, and we don't want to eat
all source ports.
The solution is a bit complex and applies to DONE/TUNNEL states :
1) disable automatic close for everything not a tunnel and not just
keep-alive / server-close. Force-close is now covered, as is HTTP/1.0
which implicitly works in force-close mode ;
2) when processing option abortonclose, we know we can disable lingering
if the client has closed and the connection is not in tunnel mode.
Since the last case above leads to a situation where the client side reports
an error, we know the connection will not be reused, so leaving the flag on
the stream-interface is safe. A client closing in the middle of the data
transmission already aborts the transaction so this case is not a problem.
This fix must be backported to 1.5 where the problem was detected.
(cherry picked from commit bbfb6c40854925367ae5f9e8b22c5c9a18dc69d5)
---
src/proto_http.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/proto_http.c b/src/proto_http.c
index 0ac3a47..5db64b5 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -5452,9 +5452,10 @@ int http_request_forward_body(struct session *s, struct channel *req, int an_bit
msg->sov -= msg->next;
msg->next = 0;
- /* for keep-alive we don't want to forward closes on DONE */
- if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
- (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL)
+ /* we don't want to forward closes on DONE except in
+ * tunnel mode.
+ */
+ if ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN)
channel_dont_close(req);
if (http_resync_states(s)) {
/* some state changes occurred, maybe the analyser
@@ -5478,10 +5479,15 @@ int http_request_forward_body(struct session *s, struct channel *req, int an_bit
* want to monitor the client's connection and forward
* any shutdown notification to the server, which will
* decide whether to close or to go on processing the
- * request.
+ * request. We only do that in tunnel mode, and not in
+ * other modes since it can be abused to exhaust source
+ * ports.
*/
if (s->be->options & PR_O_ABRT_CLOSE) {
channel_auto_read(req);
+ if ((req->flags & (CF_SHUTR|CF_READ_NULL)) &&
+ ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN))
+ s->si[1].flags |= SI_FL_NOLINGER;
channel_auto_close(req);
}
else if (s->txn.meth == HTTP_METH_POST) {
--
2.0.5

View File

@ -0,0 +1,28 @@
From 68e4fc2b9910dd090c5e729203b72444f75aaa75 Mon Sep 17 00:00:00 2001
From: Baptiste Assmann <bedis9@gmail.com>
Date: Fri, 1 May 2015 08:09:29 +0200
Subject: [PATCH 3/8] BUG/MINOR: check: fix tcpcheck error message
add the keyword 'string' when required (error in a tcpcheck expect
string)
(cherry picked from commit 96a5c9b57738c05ecce7822093b9c4118123dc1e)
---
src/checks.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/checks.c b/src/checks.c
index 71debb6..8b53f97 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -614,7 +614,7 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi
}
else if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_EXPECT) {
if (check->last_started_step->string)
- chunk_appendf(chk, " (string '%s')", check->last_started_step->string);
+ chunk_appendf(chk, " (expect string '%s')", check->last_started_step->string);
else if (check->last_started_step->expect_regex)
chunk_appendf(chk, " (expect regex)");
}
--
2.0.5

View File

@ -0,0 +1,178 @@
From 4f889006269e4d3f802de46f280ed198a15e3a69 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Wed, 13 May 2015 11:23:01 +0200
Subject: [PATCH 4/8] CLEANUP: checks: fix double usage of cur / current_step
in tcp-checks
This cleanup is a preliminary requirement to the upcoming fixes for
the bug that affect tcp-check's improper use of lists. It will have
to be backported to 1.5 though it will not easily apply.
There are two variables pointing to the current rule within the loop,
and either one or the other is used depending on the code blocks,
making it much harder to apply checks to fix the list walking bug.
So first get rid of "cur" and only focus on current_step.
(cherry picked from commit ce8c42a37a44a1e0cb94e81abb7cc2baf3d0ef80)
[wt: 1.5 doesn't have comments so this patch differs significantly
from 1.6, but it's needed for the next batch of fixes]
---
src/checks.c | 57 ++++++++++++++++++++++++++++-----------------------------
1 file changed, 28 insertions(+), 29 deletions(-)
diff --git a/src/checks.c b/src/checks.c
index 8b53f97..cfdfe8c 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1859,7 +1859,7 @@ static int tcpcheck_get_step_id(struct server *s)
static void tcpcheck_main(struct connection *conn)
{
char *contentptr;
- struct tcpcheck_rule *cur, *next;
+ struct tcpcheck_rule *next;
int done = 0, ret = 0;
struct check *check = conn->owner;
struct server *s = check->server;
@@ -1916,15 +1916,11 @@ static void tcpcheck_main(struct connection *conn)
check->bo->o = 0;
check->bi->p = check->bi->data;
check->bi->i = 0;
- cur = check->current_step = LIST_ELEM(head->n, struct tcpcheck_rule *, list);
+ check->current_step = LIST_ELEM(head->n, struct tcpcheck_rule *, list);
t->expire = tick_add(now_ms, MS_TO_TICKS(check->inter));
if (s->proxy->timeout.check)
t->expire = tick_add_ifset(now_ms, s->proxy->timeout.check);
}
- /* keep on processing step */
- else {
- cur = check->current_step;
- }
/* It's only the rules which will enable send/recv */
__conn_data_stop_both(conn);
@@ -1934,7 +1930,7 @@ static void tcpcheck_main(struct connection *conn)
* or if we're about to send a string that does not fit in the remaining space.
*/
if (check->bo->o &&
- (&cur->list == head ||
+ (&check->current_step->list == head ||
check->current_step->action != TCPCHK_ACT_SEND ||
check->current_step->string_len >= buffer_total_space(check->bo))) {
@@ -1949,14 +1945,17 @@ static void tcpcheck_main(struct connection *conn)
}
/* did we reach the end ? If so, let's check that everything was sent */
- if (&cur->list == head) {
+ if (&check->current_step->list == head) {
if (check->bo->o)
goto out_need_io;
break;
}
- /* have 'next' point to the next rule or NULL if we're on the last one */
- next = (struct tcpcheck_rule *)cur->list.n;
+ /* have 'next' point to the next rule or NULL if we're on the
+ * last one, connect() needs this.
+ */
+ next = (struct tcpcheck_rule *)check->current_step->list.n;
+
if (&next->list == head)
next = NULL;
@@ -2058,8 +2057,7 @@ static void tcpcheck_main(struct connection *conn)
}
/* allow next rule */
- cur = (struct tcpcheck_rule *)cur->list.n;
- check->current_step = cur;
+ check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
/* don't do anything until the connection is established */
if (!(conn->flags & CO_FL_CONNECTED)) {
@@ -2113,8 +2111,7 @@ static void tcpcheck_main(struct connection *conn)
*check->bo->p = '\0'; /* to make gdb output easier to read */
/* go to next rule and try to send */
- cur = (struct tcpcheck_rule *)cur->list.n;
- check->current_step = cur;
+ check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
} /* end 'send' */
else if (check->current_step->action == TCPCHK_ACT_EXPECT) {
if (unlikely(check->result == CHK_RES_FAILED))
@@ -2167,14 +2164,14 @@ static void tcpcheck_main(struct connection *conn)
goto out_end_tcpcheck;
}
- if (!done && (cur->string != NULL) && (check->bi->i < cur->string_len) )
+ if (!done && (check->current_step->string != NULL) && (check->bi->i < check->current_step->string_len) )
continue; /* try to read more */
tcpcheck_expect:
- if (cur->string != NULL)
- ret = my_memmem(contentptr, check->bi->i, cur->string, cur->string_len) != NULL;
- else if (cur->expect_regex != NULL)
- ret = regex_exec(cur->expect_regex, contentptr);
+ if (check->current_step->string != NULL)
+ ret = my_memmem(contentptr, check->bi->i, check->current_step->string, check->current_step->string_len) != NULL;
+ else if (check->current_step->expect_regex != NULL)
+ ret = regex_exec(check->current_step->expect_regex, contentptr);
if (!ret && !done)
continue; /* try to read more */
@@ -2182,11 +2179,11 @@ static void tcpcheck_main(struct connection *conn)
/* matched */
if (ret) {
/* matched but we did not want to => ERROR */
- if (cur->inverse) {
+ if (check->current_step->inverse) {
/* we were looking for a string */
- if (cur->string != NULL) {
+ if (check->current_step->string != NULL) {
chunk_printf(&trash, "TCPCHK matched unwanted content '%s' at step %d",
- cur->string, tcpcheck_get_step_id(s));
+ check->current_step->string, tcpcheck_get_step_id(s));
}
else {
/* we were looking for a regex */
@@ -2198,8 +2195,9 @@ static void tcpcheck_main(struct connection *conn)
}
/* matched and was supposed to => OK, next step */
else {
- cur = (struct tcpcheck_rule*)cur->list.n;
- check->current_step = cur;
+ /* allow next rule */
+ check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+
if (check->current_step->action == TCPCHK_ACT_EXPECT)
goto tcpcheck_expect;
__conn_data_stop_recv(conn);
@@ -2208,9 +2206,10 @@ static void tcpcheck_main(struct connection *conn)
else {
/* not matched */
/* not matched and was not supposed to => OK, next step */
- if (cur->inverse) {
- cur = (struct tcpcheck_rule*)cur->list.n;
- check->current_step = cur;
+ if (check->current_step->inverse) {
+ /* allow next rule */
+ check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+
if (check->current_step->action == TCPCHK_ACT_EXPECT)
goto tcpcheck_expect;
__conn_data_stop_recv(conn);
@@ -2218,9 +2217,9 @@ static void tcpcheck_main(struct connection *conn)
/* not matched but was supposed to => ERROR */
else {
/* we were looking for a string */
- if (cur->string != NULL) {
+ if (check->current_step->string != NULL) {
chunk_printf(&trash, "TCPCHK did not match content '%s' at step %d",
- cur->string, tcpcheck_get_step_id(s));
+ check->current_step->string, tcpcheck_get_step_id(s));
}
else {
/* we were looking for a regex */
--
2.0.5

View File

@ -0,0 +1,53 @@
From b94a6d5a37499ce6649ad58f4a8c4664779abd8b Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Wed, 13 May 2015 11:38:17 +0200
Subject: [PATCH 5/8] BUG/MEDIUM: checks: do not dereference head of a
tcp-check at the end
When the end of the list is reached, the current step's action is checked
to know if we must poll or not. Unfortunately, the main reason for going
there is that we walked past the end of list and current_step points to
the head. We cannot dereference ->action since it does not belong to this
structure and can definitely crash if the address is not mapped.
This bug is unlikely to cause a crash since the action appears just after
the list, and corresponds to the "char *check_req" pointer in the proxy
struct, and it seems that we can't go there with current_step being null.
At worst it can cause the check to register for recv events.
This fix needs to be backported to 1.5 since the code is incorrect there
as well.
(cherry picked from commit 53c5a049e1f4dbf67412472e23690dc6b3c8d0f8)
---
src/checks.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/checks.c b/src/checks.c
index cfdfe8c..a887be1 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -2237,10 +2237,12 @@ static void tcpcheck_main(struct connection *conn)
goto out_end_tcpcheck;
out_need_io:
+ /* warning, current_step may now point to the head */
if (check->bo->o)
__conn_data_want_send(conn);
- if (check->current_step->action == TCPCHK_ACT_EXPECT)
+ if (&check->current_step->list != head &&
+ check->current_step->action == TCPCHK_ACT_EXPECT)
__conn_data_want_recv(conn);
return;
@@ -2256,7 +2258,6 @@ static void tcpcheck_main(struct connection *conn)
conn->flags |= CO_FL_ERROR;
__conn_data_stop_both(conn);
-
return;
}
--
2.0.5

View File

@ -0,0 +1,82 @@
From ebb2bceb34d7787453548627ed0e99c60354672b Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Wed, 13 May 2015 11:59:14 +0200
Subject: [PATCH 6/8] CLEANUP: checks: simplify the loop processing of
tcp-checks
There is some unobvious redundancy between the various ways we can leave
the loop. Some of them can be factored out. So now we leave the loop when
we can't go further, whether it's caused by reaching the end of the rules
or by a blocking I/O.
(cherry picked from commit 263013d031d754c9f96de0d0cb5afcc011af6441)
[wt: this patch is required for the next fix]
---
src/checks.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/checks.c b/src/checks.c
index a887be1..a0c42f2 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1926,8 +1926,10 @@ static void tcpcheck_main(struct connection *conn)
__conn_data_stop_both(conn);
while (1) {
- /* we have to try to flush the output buffer before reading, at the end,
- * or if we're about to send a string that does not fit in the remaining space.
+ /* We have to try to flush the output buffer before reading, at
+ * the end, or if we're about to send a string that does not fit
+ * in the remaining space. That explains why we break out of the
+ * loop after this control.
*/
if (check->bo->o &&
(&check->current_step->list == head ||
@@ -1940,16 +1942,12 @@ static void tcpcheck_main(struct connection *conn)
__conn_data_stop_both(conn);
goto out_end_tcpcheck;
}
- goto out_need_io;
+ break;
}
}
- /* did we reach the end ? If so, let's check that everything was sent */
- if (&check->current_step->list == head) {
- if (check->bo->o)
- goto out_need_io;
+ if (&check->current_step->list == head)
break;
- }
/* have 'next' point to the next rule or NULL if we're on the
* last one, connect() needs this.
@@ -2131,7 +2129,7 @@ static void tcpcheck_main(struct connection *conn)
}
}
else
- goto out_need_io;
+ break;
}
/* mark the step as started */
@@ -2233,10 +2231,14 @@ static void tcpcheck_main(struct connection *conn)
} /* end expect */
} /* end loop over double chained step list */
- set_server_check_status(check, HCHK_STATUS_L7OKD, "(tcp-check)");
- goto out_end_tcpcheck;
+ /* We're waiting for some I/O to complete, we've reached the end of the
+ * rules, or both. Do what we have to do, otherwise we're done.
+ */
+ if (&check->current_step->list == head && !check->bo->o) {
+ set_server_check_status(check, HCHK_STATUS_L7OKD, "(tcp-check)");
+ goto out_end_tcpcheck;
+ }
- out_need_io:
/* warning, current_step may now point to the head */
if (check->bo->o)
__conn_data_want_send(conn);
--
2.0.5

View File

@ -0,0 +1,90 @@
From 97fccc87f1297d189ee80735e5b8746c34956eda Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Wed, 13 May 2015 12:08:21 +0200
Subject: [PATCH 7/8] BUG/MAJOR: checks: always check for end of list before
proceeding
This is the most important fix of this series. There's a risk of endless
loop and crashes caused by the fact that we go past the head of the list
when skipping to next rule, without checking if it's still a valid element.
Most of the time, the ->action field is checked, which points to the proxy's
check_req pointer (generally NULL), meaning the element is confused with a
TCPCHK_ACT_SEND action.
The situation was accidently made worse with the addition of tcp-check
comment since it also skips list elements. However, since the action that
makes it go forward is TCPCHK_ACT_COMMENT (3), there's little chance to
see this as a valid pointer, except on 64-bit machines where it can match
the end of a check_req string pointer.
This fix heavily depends on previous cleanup and both must be backported
to 1.5 where the bug is present.
(cherry picked from commit f2c87353a7f8160930b5f342bb6d6ad0991ee3d1)
[wt: this patch differs significantly from 1.6 since we don't have comments]
---
src/cfgparse.c | 4 +++-
src/checks.c | 12 ++++++++++++
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 746c7eb..dba59d1 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -4368,7 +4368,9 @@ stats_error_parsing:
l = (struct list *)&curproxy->tcpcheck_rules;
if (l->p != l->n) {
tcpcheck = (struct tcpcheck_rule *)l->n;
- if (tcpcheck && tcpcheck->action != TCPCHK_ACT_CONNECT) {
+
+ if (&tcpcheck->list != &curproxy->tcpcheck_rules
+ && tcpcheck->action != TCPCHK_ACT_CONNECT) {
Alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
file, linenum);
err_code |= ERR_ALERT | ERR_FATAL;
diff --git a/src/checks.c b/src/checks.c
index a0c42f2..e13d561 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -2057,6 +2057,9 @@ static void tcpcheck_main(struct connection *conn)
/* allow next rule */
check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+ if (&check->current_step->list == head)
+ break;
+
/* don't do anything until the connection is established */
if (!(conn->flags & CO_FL_CONNECTED)) {
/* update expire time, should be done by process_chk */
@@ -2110,6 +2113,9 @@ static void tcpcheck_main(struct connection *conn)
/* go to next rule and try to send */
check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+
+ if (&check->current_step->list == head)
+ break;
} /* end 'send' */
else if (check->current_step->action == TCPCHK_ACT_EXPECT) {
if (unlikely(check->result == CHK_RES_FAILED))
@@ -2196,6 +2202,9 @@ static void tcpcheck_main(struct connection *conn)
/* allow next rule */
check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+ if (&check->current_step->list == head)
+ break;
+
if (check->current_step->action == TCPCHK_ACT_EXPECT)
goto tcpcheck_expect;
__conn_data_stop_recv(conn);
@@ -2208,6 +2217,9 @@ static void tcpcheck_main(struct connection *conn)
/* allow next rule */
check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+ if (&check->current_step->list == head)
+ break;
+
if (check->current_step->action == TCPCHK_ACT_EXPECT)
goto tcpcheck_expect;
__conn_data_stop_recv(conn);
--
2.0.5

View File

@ -0,0 +1,116 @@
From 5bff05986c501d9ffb67873b60472f9c2a2e41be Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Wed, 13 May 2015 12:24:53 +0200
Subject: [PATCH 8/8] BUG/MEDIUM: checks: do not dereference a list as a
tcpcheck struct
The method used to skip to next rule in the list is wrong, it assumes
that the list element starts at the same offset as the rule. It happens
to be true on most architectures since the list is the first element for
now but it's definitely wrong. Now the code doesn't crash anymore when
the struct list is moved anywhere else in the struct tcpcheck_rule.
This fix must be backported to 1.5.
(cherry picked from commit 5581c27b579cbfc53afb0ca04cdeebe7e2200131)
[wt: changes from 1.6 : no tcp-check comments, check becomes s->proxy]
---
src/cfgparse.c | 18 +++++++-----------
src/checks.c | 15 +++++++++------
2 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/src/cfgparse.c b/src/cfgparse.c
index dba59d1..e04eff8 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -4362,20 +4362,16 @@ stats_error_parsing:
const char *ptr_arg;
int cur_arg;
struct tcpcheck_rule *tcpcheck;
- struct list *l;
/* check if first rule is also a 'connect' action */
- l = (struct list *)&curproxy->tcpcheck_rules;
- if (l->p != l->n) {
- tcpcheck = (struct tcpcheck_rule *)l->n;
+ tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
- if (&tcpcheck->list != &curproxy->tcpcheck_rules
- && tcpcheck->action != TCPCHK_ACT_CONNECT) {
- Alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
- file, linenum);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto out;
- }
+ if (&tcpcheck->list != &curproxy->tcpcheck_rules
+ && tcpcheck->action != TCPCHK_ACT_CONNECT) {
+ Alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
+ file, linenum);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
}
cur_arg = 2;
diff --git a/src/checks.c b/src/checks.c
index e13d561..27a23b2 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1444,7 +1444,10 @@ static int connect_chk(struct task *t)
quickack = check->type == 0 || check->type == PR_O2_TCPCHK_CHK;
if (check->type == PR_O2_TCPCHK_CHK && !LIST_ISEMPTY(&s->proxy->tcpcheck_rules)) {
- struct tcpcheck_rule *r = (struct tcpcheck_rule *) s->proxy->tcpcheck_rules.n;
+ struct tcpcheck_rule *r;
+
+ r = LIST_NEXT(&s->proxy->tcpcheck_rules, struct tcpcheck_rule *, list);
+
/* if first step is a 'connect', then tcpcheck_main must run it */
if (r->action == TCPCHK_ACT_CONNECT) {
tcpcheck_main(conn);
@@ -1952,7 +1955,7 @@ static void tcpcheck_main(struct connection *conn)
/* have 'next' point to the next rule or NULL if we're on the
* last one, connect() needs this.
*/
- next = (struct tcpcheck_rule *)check->current_step->list.n;
+ next = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
if (&next->list == head)
next = NULL;
@@ -2055,7 +2058,7 @@ static void tcpcheck_main(struct connection *conn)
}
/* allow next rule */
- check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+ check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
if (&check->current_step->list == head)
break;
@@ -2112,7 +2115,7 @@ static void tcpcheck_main(struct connection *conn)
*check->bo->p = '\0'; /* to make gdb output easier to read */
/* go to next rule and try to send */
- check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+ check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
if (&check->current_step->list == head)
break;
@@ -2200,7 +2203,7 @@ static void tcpcheck_main(struct connection *conn)
/* matched and was supposed to => OK, next step */
else {
/* allow next rule */
- check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+ check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
if (&check->current_step->list == head)
break;
@@ -2215,7 +2218,7 @@ static void tcpcheck_main(struct connection *conn)
/* not matched and was not supposed to => OK, next step */
if (check->current_step->inverse) {
/* allow next rule */
- check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
+ check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
if (&check->current_step->list == head)
break;
--
2.0.5

View File

@ -0,0 +1,77 @@
From 76a06b2804bcdba0fb2c19f834bdb511ce3cf344 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Wed, 20 May 2015 10:39:04 +0200
Subject: [PATCH 09/10] BUG/MEDIUM: peers: apply a random reconnection timeout
Commit 9ff95bb ("BUG/MEDIUM: peers: correctly configure the client timeout")
uncovered an old bug in the peers : upon disconnect, we reconnect immediately.
This sometimes results in both ends to do the same thing in parallel causing
a loop of connect/accept/close/close that can last several seconds. The risk
of occurrence of the trouble increases with latency, and is emphasized by the
fact that idle connections are now frequently recycled (after 5s of idle).
In order to avoid this we must apply a random delay before reconnecting.
Fortunately the mechanism already supports a reconnect delay, so here we
compute the random timeout when killing a session. The delay is 50ms plus
a random between 0 and 2 seconds. Ideally an exponential back-off would
be preferred but it's preferable to keep the fix simple.
This bug was reported by Marco Corte.
This fix must be backported to 1.5 since the fix above was backported into
1.5.12.
(cherry picked from commit b4e34da692d8a7f6837ad16b3389f5830dbc11d2)
---
src/peers.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/peers.c b/src/peers.c
index b196d88..159f0a4 100644
--- a/src/peers.c
+++ b/src/peers.c
@@ -1063,6 +1063,7 @@ static void peer_session_forceshutdown(struct session * session)
{
struct stream_interface *oldsi = NULL;
struct appctx *appctx = NULL;
+ struct peer_session *ps;
int i;
for (i = 0; i <= 1; i++) {
@@ -1079,6 +1080,14 @@ static void peer_session_forceshutdown(struct session * session)
if (!appctx)
return;
+ ps = (struct peer_session *)appctx->ctx.peers.ptr;
+ /* we're killing a connection, we must apply a random delay before
+ * retrying otherwise the other end will do the same and we can loop
+ * for a while.
+ */
+ if (ps)
+ ps->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + random() % 2000));
+
/* call release to reinit resync states if needed */
peer_session_release(oldsi);
appctx->st0 = PEER_SESS_ST_END;
@@ -1352,8 +1361,8 @@ static struct task *process_peer_sync(struct task * task)
if (!ps->session) {
/* no active session */
if (ps->statuscode == 0 ||
- ps->statuscode == PEER_SESS_SC_SUCCESSCODE ||
((ps->statuscode == PEER_SESS_SC_CONNECTCODE ||
+ ps->statuscode == PEER_SESS_SC_SUCCESSCODE ||
ps->statuscode == PEER_SESS_SC_CONNECTEDCODE) &&
tick_is_expired(ps->reconnect, now_ms))) {
/* connection never tried
@@ -1364,8 +1373,7 @@ static struct task *process_peer_sync(struct task * task)
/* retry a connect */
ps->session = peer_session_create(ps->peer, ps);
}
- else if (ps->statuscode == PEER_SESS_SC_CONNECTCODE ||
- ps->statuscode == PEER_SESS_SC_CONNECTEDCODE) {
+ else if (!tick_is_expired(ps->reconnect, now_ms)) {
/* If previous session failed during connection
* but reconnection timer is not expired */
--
2.0.5

View File

@ -0,0 +1,33 @@
From ac372e18c422841a9f1197b4238637c470e8edca Mon Sep 17 00:00:00 2001
From: Pavlos Parissis <pavlos.parissis@gmail.com>
Date: Sat, 2 May 2015 20:30:44 +0200
Subject: [PATCH 10/10] DOC: Update doc about weight, act and bck fields in the
statistics
Reorder description of the mentioned fields in order to match the
order of types
(cherry picked from commit 1f673c72c11d011bbd24e309d3155384eddf7a46)
---
doc/configuration.txt | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/doc/configuration.txt b/doc/configuration.txt
index a9d497e..6f5eeb1 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -13240,9 +13240,9 @@ S (Servers).
server. The server value counts the number of times that server was
switched away from.
17. status [LFBS]: status (UP/DOWN/NOLB/MAINT/MAINT(via)...)
- 18. weight [..BS]: server weight (server), total weight (backend)
- 19. act [..BS]: server is active (server), number of active servers (backend)
- 20. bck [..BS]: server is backup (server), number of backup servers (backend)
+ 18. weight [..BS]: total weight (backend), server weight (server)
+ 19. act [..BS]: number of active servers (backend), server is active (server)
+ 20. bck [..BS]: number of backup servers (backend), server is backup (server)
21. chkfail [...S]: number of failed checks. (Only counts checks failed when
the server is up.)
22. chkdown [..BS]: number of UP->DOWN transitions. The backend counter counts
--
2.0.5

View File

@ -0,0 +1,64 @@
From 269a02fbb332da8faf6c2a614d45d5b5018816d1 Mon Sep 17 00:00:00 2001
From: Remi Gacogne <rgacogne@aquaray.fr>
Date: Thu, 28 May 2015 16:39:47 +0200
Subject: [PATCH 11/14] MINOR: ssl: add a destructor to free allocated SSL
ressources
Using valgrind or another memory leak tracking tool is easier
when the memory internally allocated by OpenSSL is cleanly released
at shutdown.
(cherry picked from commit d3a23c3eb8c0950d26204568a133207099923494)
---
src/ssl_sock.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index d0f4d01..a78fc6a 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -4717,6 +4717,42 @@ static void __ssl_sock_init(void)
cfg_register_keywords(&cfg_kws);
}
+__attribute__((destructor))
+static void __ssl_sock_deinit(void)
+{
+#ifndef OPENSSL_NO_DH
+ if (local_dh_1024) {
+ DH_free(local_dh_1024);
+ local_dh_1024 = NULL;
+ }
+
+ if (local_dh_2048) {
+ DH_free(local_dh_2048);
+ local_dh_2048 = NULL;
+ }
+
+ if (local_dh_4096) {
+ DH_free(local_dh_4096);
+ local_dh_4096 = NULL;
+ }
+
+ if (local_dh_8192) {
+ DH_free(local_dh_8192);
+ local_dh_8192 = NULL;
+ }
+#endif
+
+ ERR_remove_state(0);
+ ERR_free_strings();
+
+ EVP_cleanup();
+
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+ CRYPTO_cleanup_all_ex_data();
+#endif
+}
+
+
/*
* Local variables:
* c-indent-level: 8
--
2.0.5

View File

@ -0,0 +1,98 @@
From 5d769ca828fdb055052b3dbc232864bdf2853c9f Mon Sep 17 00:00:00 2001
From: Remi Gacogne <rgacogne@aquaray.fr>
Date: Thu, 28 May 2015 16:23:00 +0200
Subject: [PATCH 12/14] BUG/MEDIUM: ssl: fix tune.ssl.default-dh-param value
being overwritten
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Hervé Commowick reported that the logic used to avoid complaining about
ssl-default-dh-param not being set when static DH params are present
in the certificate file was clearly wrong when more than one sni_ctx
is used.
This patch stores whether static DH params are being used for each
SSL_CTX individually, and does not overwrite the value of
tune.ssl.default-dh-param.
(cherry picked from commit 4f902b88323927c9d25d391a809e3678ac31df41)
---
src/ssl_sock.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index a78fc6a..0f7819b 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -47,6 +47,9 @@
#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
#include <openssl/ocsp.h>
#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
#include <common/buffer.h>
#include <common/compat.h>
@@ -107,6 +110,7 @@ int sslconns = 0;
int totalsslconns = 0;
#ifndef OPENSSL_NO_DH
+static int ssl_dh_ptr_index = -1;
static DH *local_dh_1024 = NULL;
static DH *local_dh_2048 = NULL;
static DH *local_dh_4096 = NULL;
@@ -1076,10 +1080,12 @@ int ssl_sock_load_dh_params(SSL_CTX *ctx, const char *file)
if (dh) {
ret = 1;
SSL_CTX_set_tmp_dh(ctx, dh);
- /* Setting ssl default dh param to the size of the static DH params
- found in the file. This way we know that there is no use
- complaining later about ssl-default-dh-param not being set. */
- global.tune.ssl_default_dh_param = DH_size(dh) * 8;
+
+ if (ssl_dh_ptr_index >= 0) {
+ /* store a pointer to the DH params to avoid complaining about
+ ssl-default-dh-param not being set for this SSL_CTX */
+ SSL_CTX_set_ex_data(ctx, ssl_dh_ptr_index, dh);
+ }
}
else {
/* Clear openssl global errors stack */
@@ -1274,6 +1280,12 @@ static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf
* the tree, so it will be discovered and cleaned in time.
*/
#ifndef OPENSSL_NO_DH
+ /* store a NULL pointer to indicate we have not yet loaded
+ a custom DH param file */
+ if (ssl_dh_ptr_index >= 0) {
+ SSL_CTX_set_ex_data(ctx, ssl_dh_ptr_index, NULL);
+ }
+
ret = ssl_sock_load_dh_params(ctx, path);
if (ret < 0) {
if (err)
@@ -1593,7 +1605,9 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy
/* If tune.ssl.default-dh-param has not been set and
no static DH params were in the certificate file. */
- if (global.tune.ssl_default_dh_param == 0) {
+ if (global.tune.ssl_default_dh_param == 0 &&
+ (ssl_dh_ptr_index == -1 ||
+ SSL_CTX_get_ex_data(ctx, ssl_dh_ptr_index) == NULL)) {
ciphers = ctx->cipher_list;
if (ciphers) {
@@ -4715,6 +4729,10 @@ static void __ssl_sock_init(void)
bind_register_keywords(&bind_kws);
srv_register_keywords(&srv_kws);
cfg_register_keywords(&cfg_kws);
+
+#ifndef OPENSSL_NO_DH
+ ssl_dh_ptr_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+#endif
}
__attribute__((destructor))
--
2.0.5

View File

@ -0,0 +1,29 @@
From 629b1c000b26f0031246b9b529680b275a14118f Mon Sep 17 00:00:00 2001
From: William Lallemand <wlallemand@haproxy.com>
Date: Thu, 28 May 2015 18:02:48 +0200
Subject: [PATCH 13/14] BUG/MINOR: cfgparse: fix typo in 'option httplog' error
message
The error message was displaying the wrong argument when 'option
httplog' took a wrong argument.
(cherry picked from commit 77063bc0c6ceb4257c4e2c08411811ecc48be1aa)
---
src/cfgparse.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cfgparse.c b/src/cfgparse.c
index e04eff8..3c3383d 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -3792,7 +3792,7 @@ stats_error_parsing:
curproxy->options2 |= PR_O2_CLFLOG;
logformat = clf_http_log_format;
} else {
- Alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[2]);
+ Alert("parsing [%s:%d] : keyword '%s' only supports option 'clf'.\n", file, linenum, args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
--
2.0.5

View File

@ -0,0 +1,41 @@
From faf3315f77c527e6e1d027deb7e853cdf6af5858 Mon Sep 17 00:00:00 2001
From: William Lallemand <wlallemand@haproxy.com>
Date: Thu, 28 May 2015 18:03:51 +0200
Subject: [PATCH 14/14] BUG/MEDIUM: cfgparse: segfault when userlist is misused
If the 'userlist' keyword parsing returns an error and no userlist were
previously created. The parsing of 'user' and 'group' leads to NULL
derefence.
The userlist pointer is now tested to prevent this issue.
(cherry picked from commit 4ac9f546120d42be8147e3d90588e7b9738af0cc)
---
src/cfgparse.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 3c3383d..392a78d 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -5668,6 +5668,9 @@ cfg_parse_users(const char *file, int linenum, char **args, int kwm)
goto out;
}
+ if (!userlist)
+ goto out;
+
for (ag = userlist->groups; ag; ag = ag->next)
if (!strcmp(ag->name, args[1])) {
Warning("parsing [%s:%d]: ignoring duplicated group '%s' in userlist '%s'.\n",
@@ -5718,6 +5721,8 @@ cfg_parse_users(const char *file, int linenum, char **args, int kwm)
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
+ if (!userlist)
+ goto out;
for (newuser = userlist->users; newuser; newuser = newuser->next)
if (!strcmp(newuser->user, args[1])) {
--
2.0.5