SHA256
1
0
forked from pool/haproxy

Accepting request 309522 from network:ha-clustering:Factory

1

OBS-URL: https://build.opensuse.org/request/show/309522
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/haproxy?expand=0&rev=29
This commit is contained in:
Dominique Leuenberger 2015-06-02 08:08:16 +00:00 committed by Git OBS Bridge
parent 4341af3d61
commit bc564798e8
11 changed files with 795 additions and 0 deletions

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.1.4

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.1.4

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/9] 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.3.7

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/9] 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.3.7

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/9] 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.3.7

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/9] 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.3.7

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/9] 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.3.7

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/9] 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.3.7

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 9/9] 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.3.7

View File

@ -1,3 +1,34 @@
-------------------------------------------------------------------
Mon May 25 09:34:58 UTC 2015 - kgronlund@suse.com
- BUG/MINOR: check: fix tcpcheck error message
- CLEANUP: checks: fix double usage of cur / current_step in tcp-checks
- BUG/MEDIUM: checks: do not dereference head of a tcp-check at the end
- CLEANUP: checks: simplify the loop processing of tcp-checks
- BUG/MAJOR: checks: always check for end of list before proceeding
- BUG/MEDIUM: checks: do not dereference a list as a tcpcheck struct
- BUG/MEDIUM: peers: apply a random reconnection timeout
- Add 0003-BUG-MINOR-check-fix-tcpcheck-error-message.patch
- Add 0004-CLEANUP-checks-fix-double-usage-of-cur-current_step-.patch
- Add 0005-BUG-MEDIUM-checks-do-not-dereference-head-of-a-tcp-c.patch
- Add 0006-CLEANUP-checks-simplify-the-loop-processing-of-tcp-c.patch
- Add 0007-BUG-MAJOR-checks-always-check-for-end-of-list-before.patch
- Add 0008-BUG-MEDIUM-checks-do-not-dereference-a-list-as-a-tcp.patch
- Add 0009-BUG-MEDIUM-peers-apply-a-random-reconnection-timeout.patch
-------------------------------------------------------------------
Mon May 11 19:27:33 UTC 2015 - mrueckert@suse.de
- added 0002-BUG-MEDIUM-http-don-t-forward-client-shutdown-withou.patch
BUG/MEDIUM: http: don't forward client shutdown without NOLINGER
except for tunnels
-------------------------------------------------------------------
Mon May 4 22:02:30 UTC 2015 - mrueckert@suse.de
- added first patch from the 1.5 branch after the update:
0001-BUG-MEDIUM-stats-properly-initialize-the-scope-befor.patch
-------------------------------------------------------------------
Sat May 2 22:17:57 UTC 2015 - mrueckert@suse.de

View File

@ -61,6 +61,23 @@ Patch1: haproxy-1.2.16_config_haproxy_user.patch
Patch2: haproxy-makefile_lib.patch
Patch3: sec-options.patch
Patch4: haproxy-1.5.8-fix-bashisms.patch
Patch5: 0001-BUG-MEDIUM-stats-properly-initialize-the-scope-befor.patch
Patch6: 0002-BUG-MEDIUM-http-don-t-forward-client-shutdown-withou.patch
# PATCH-FIX-UPSTREAM: BUG/MINOR: check: fix tcpcheck error message
Patch7: 0003-BUG-MINOR-check-fix-tcpcheck-error-message.patch
# PATCH-FIX-UPSTREAM: CLEANUP: checks: fix double usage of cur / current_step in tcp-checks
Patch8: 0004-CLEANUP-checks-fix-double-usage-of-cur-current_step-.patch
# PATCH-FIX-UPSTREAM: BUG/MEDIUM: checks: do not dereference head of a tcp-check at the end
Patch9: 0005-BUG-MEDIUM-checks-do-not-dereference-head-of-a-tcp-c.patch
# PATCH-FIX-UPSTREAM: CLEANUP: checks: simplify the loop processing of tcp-checks
Patch10: 0006-CLEANUP-checks-simplify-the-loop-processing-of-tcp-c.patch
# PATCH-FIX-UPSTREAM: BUG/MAJOR: checks: always check for end of list before proceeding
Patch11: 0007-BUG-MAJOR-checks-always-check-for-end-of-list-before.patch
# PATCH-FIX-UPSTREAM: BUG/MEDIUM: checks: do not dereference a list as a tcpcheck struct
Patch12: 0008-BUG-MEDIUM-checks-do-not-dereference-a-list-as-a-tcp.patch
# PATCH-FIX-UPSTREAM: BUG/MEDIUM: peers: apply a random reconnection timeout
Patch13: 0009-BUG-MEDIUM-peers-apply-a-random-reconnection-timeout.patch
#
Source99: haproxy-rpmlintrc
#
@ -95,6 +112,15 @@ the most work done from every CPU cycle.
%patch2
%patch3
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%build
%{__make} \