1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

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.
This commit is contained in:
Simon Tatham 2022-02-19 12:04:09 +00:00
parent 099d00c4ac
commit 6c754822bc
3 changed files with 34 additions and 7 deletions

View File

@ -670,9 +670,9 @@ static void proxy_http_process_queue(ProxyNegotiator *pn)
/* 407 is Proxy Authentication Required, which we may be /* 407 is Proxy Authentication Required, which we may be
* able to do something about. */ * able to do something about. */
if (s->connection_close) { if (s->connection_close) {
pn->error = dupprintf("HTTP proxy closed connection after " /* If we got 407 + connection closed, reconnect before
"asking for authentication"); * sending our next request. */
crStopV; pn->reconnect = true;
} }
/* If the best we can do is report some kind of error from /* If the best we can do is report some kind of error from

View File

@ -99,6 +99,7 @@ static void sk_proxy_close (Socket *s)
ProxySocket *ps = container_of(s, ProxySocket, sock); ProxySocket *ps = container_of(s, ProxySocket, sock);
sk_close(ps->sub_socket); sk_close(ps->sub_socket);
sk_addr_free(ps->proxy_addr);
sk_addr_free(ps->remote_addr); sk_addr_free(ps->remote_addr);
proxy_negotiator_cleanup(ps); proxy_negotiator_cleanup(ps);
bufchain_clear(&ps->output_from_negotiator); bufchain_clear(&ps->output_from_negotiator);
@ -223,6 +224,16 @@ static void proxy_negotiate(ProxySocket *ps)
return; 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)) { while (bufchain_size(&ps->output_from_negotiator)) {
ptrlen data = bufchain_prefix(&ps->output_from_negotiator); ptrlen data = bufchain_prefix(&ps->output_from_negotiator);
sk_write(ps->sub_socket, data.ptr, data.len); 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, /* create the actual socket we will be using,
* connected to our proxy server and port. * connected to our proxy server and port.
*/ */
ps->sub_socket = sk_new(proxy_addr, ps->proxy_addr = sk_addr_dup(proxy_addr);
conf_get_int(conf, CONF_proxy_port), ps->proxy_port = conf_get_int(conf, CONF_proxy_port);
privport, oobinline, ps->proxy_privport = privport;
nodelay, keepalive, &ps->plugimpl); 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) if (sk_socket_error(ps->sub_socket) != NULL)
return &ps->sock; return &ps->sock;

View File

@ -22,6 +22,11 @@ struct ProxySocket {
SockAddr *remote_addr; SockAddr *remote_addr;
int remote_port; 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_output_data;
bufchain pending_oob_output_data; bufchain pending_oob_output_data;
bufchain pending_input_data; bufchain pending_input_data;
@ -68,6 +73,11 @@ struct ProxyNegotiator {
/* Set to report user abort during proxy negotiation. */ /* Set to report user abort during proxy negotiation. */
bool aborted; 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 { struct ProxyNegotiatorVT {