From 6c754822bca7284374f15ba90392e598909f9833 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 19 Feb 2022 12:04:09 +0000 Subject: [PATCH] Proxy system: ability to reconnect to the proxy server. Another awkward thing that FreeProxy does is to slam the connection shut after sending its 407 response, at least in Basic auth mode. (It keeps the connection alive in digest mode, which makes sense to me, because that's a more stateful system.) It was surprisingly easy to make the proxy code able to tolerate this! I've set it up so that a ProxyNegotiator can just set its 'reconnect' flag on return from the negotiation coroutine, and the effect will be that proxy.c makes a new connection to the same proxy server before doing anything else. In particular, you can set that flag _and_ put data in the output bufchain, and there's no problem - the output data will be queued directly into the new socket. --- proxy/http.c | 6 +++--- proxy/proxy.c | 25 +++++++++++++++++++++---- proxy/proxy.h | 10 ++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/proxy/http.c b/proxy/http.c index 761abdf6..d4797171 100644 --- a/proxy/http.c +++ b/proxy/http.c @@ -670,9 +670,9 @@ static void proxy_http_process_queue(ProxyNegotiator *pn) /* 407 is Proxy Authentication Required, which we may be * able to do something about. */ if (s->connection_close) { - pn->error = dupprintf("HTTP proxy closed connection after " - "asking for authentication"); - crStopV; + /* If we got 407 + connection closed, reconnect before + * sending our next request. */ + pn->reconnect = true; } /* If the best we can do is report some kind of error from diff --git a/proxy/proxy.c b/proxy/proxy.c index 36105097..6bedcf9b 100644 --- a/proxy/proxy.c +++ b/proxy/proxy.c @@ -99,6 +99,7 @@ static void sk_proxy_close (Socket *s) ProxySocket *ps = container_of(s, ProxySocket, sock); sk_close(ps->sub_socket); + sk_addr_free(ps->proxy_addr); sk_addr_free(ps->remote_addr); proxy_negotiator_cleanup(ps); bufchain_clear(&ps->output_from_negotiator); @@ -223,6 +224,16 @@ static void proxy_negotiate(ProxySocket *ps) return; } + if (ps->pn->reconnect) { + sk_close(ps->sub_socket); + SockAddr *proxy_addr = sk_addr_dup(ps->proxy_addr); + ps->sub_socket = sk_new(proxy_addr, ps->proxy_port, + ps->proxy_privport, ps->proxy_oobinline, + ps->proxy_nodelay, ps->proxy_keepalive, + &ps->plugimpl); + ps->pn->reconnect = false; + } + while (bufchain_size(&ps->output_from_negotiator)) { ptrlen data = bufchain_prefix(&ps->output_from_negotiator); sk_write(ps->sub_socket, data.ptr, data.len); @@ -601,10 +612,16 @@ Socket *new_connection(SockAddr *addr, const char *hostname, /* create the actual socket we will be using, * connected to our proxy server and port. */ - ps->sub_socket = sk_new(proxy_addr, - conf_get_int(conf, CONF_proxy_port), - privport, oobinline, - nodelay, keepalive, &ps->plugimpl); + ps->proxy_addr = sk_addr_dup(proxy_addr); + ps->proxy_port = conf_get_int(conf, CONF_proxy_port); + ps->proxy_privport = privport; + ps->proxy_oobinline = oobinline; + ps->proxy_nodelay = nodelay; + ps->proxy_keepalive = keepalive; + ps->sub_socket = sk_new(proxy_addr, ps->proxy_port, + ps->proxy_privport, ps->proxy_oobinline, + ps->proxy_nodelay, ps->proxy_keepalive, + &ps->plugimpl); if (sk_socket_error(ps->sub_socket) != NULL) return &ps->sock; diff --git a/proxy/proxy.h b/proxy/proxy.h index ca4a293f..72d06d49 100644 --- a/proxy/proxy.h +++ b/proxy/proxy.h @@ -22,6 +22,11 @@ struct ProxySocket { SockAddr *remote_addr; int remote_port; + /* Parameters needed to make further connections to the proxy */ + SockAddr *proxy_addr; + int proxy_port; + bool proxy_privport, proxy_oobinline, proxy_nodelay, proxy_keepalive; + bufchain pending_output_data; bufchain pending_oob_output_data; bufchain pending_input_data; @@ -68,6 +73,11 @@ struct ProxyNegotiator { /* Set to report user abort during proxy negotiation. */ bool aborted; + + /* Set to request the centralised code to make a fresh connection + * to the proxy server, e.g. because an HTTP proxy slammed the + * connection shut after sending 407 Proxy Auth Required. */ + bool reconnect; }; struct ProxyNegotiatorVT {