From 0857d7aa8f3ec1b6505da69b0143343b2d0bb077 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 29 Aug 2016 14:46:54 +0200 Subject: [PATCH] BUG/MAJOR: stream: properly mark the server address as unset on connect retry Bartosz Koninski reported that recent commit 568743a ("BUG/MEDIUM: stream-int: completely detach connection on connect error") introduced a nasty side effect during the connection retry, causing a reconnect attempt to be performed on a random address, possibly another server from another backend as shown in his reproducer. The real reason is in fact that by calling si_release_endpoint() after a failed connect attempt and not clearing the SN_ADDR_SET flag on the stream, we indicate that we continue to trust the connection's current address. So upon next connect attempt, a connection is picked from the pool and the last target address is reused. It is not very easy to reproduce it 100% reliably out of production traffic, but it's easier to see when haproxy is started with -dM to force the pools to be filled with junk, and where subsequent connections are not even attempted due to their family being incorrect. The correct fix consists in clearing the SN_ADDR_SET flag after calling si_release_endpoint() during a retry. But it outlines a deeper issue which is in fact that the target address is *stored* in the connection and its validity is stored in the stream. Until we have a better solution to store target addresses, it would be better to rely on the connection flags (CO_FL_ADDR_TO_SET) for this purpose. But it also outlines the fact that the same issue still exists in Lua sockets and in idle sockets, which fortunately are not affected by this issue. Thanks to Bartosz for providing all the elements needed to understand the problem. This fix needs to be backported to 1.6 and 1.5. --- src/stream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stream.c b/src/stream.c index 3982daab79..151bcb0b9d 100644 --- a/src/stream.c +++ b/src/stream.c @@ -580,6 +580,7 @@ static int sess_update_st_con_tcp(struct stream *s) si->state = SI_ST_CER; si_release_endpoint(si); + s->flags &= ~SF_ADDR_SET; if (si->err_type) return 0; -- 2.39.5