forked from pool/haproxy
83 lines
3.5 KiB
Diff
83 lines
3.5 KiB
Diff
|
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
|
||
|
|