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

Make ProxySocket an Interactor.

This lays all the groundwork for ProxyNegotiators to be able to issue
username and password prompts: ProxySocket now implements the
Interactor trait, it will borrow and return a Seat if one is
available, and it will present an Interactor of its own to the
ProxyNegotiator which can use it (via interactor_announce as usual) to
get a Seat to send prompts to. Also, proxy.c provides a centralised
system for making a prompts_t with an appropriate callback in it, and
dealing with the results of that callback.

No actual ProxyNegotiator implementation uses it yet, though.
This commit is contained in:
Simon Tatham 2021-11-19 11:05:14 +00:00
parent b7bf2aec74
commit 02aa5610dd
2 changed files with 99 additions and 7 deletions

View File

@ -18,6 +18,19 @@
(conf_get_int(conf, CONF_proxy_dns) == AUTO && \
conf_get_int(conf, CONF_proxy_type) != PROXY_SOCKS4))
static void proxy_negotiator_cleanup(ProxySocket *ps)
{
if (ps->pn) {
proxy_negotiator_free(ps->pn);
ps->pn = NULL;
}
if (ps->clientseat) {
interactor_return_seat(ps->clientitr);
ps->clientitr = NULL;
ps->clientseat = NULL;
}
}
/*
* Call this when proxy negotiation is complete, so that this
* socket can begin working normally.
@ -26,9 +39,7 @@ void proxy_activate(ProxySocket *ps)
{
size_t output_before, output_after;
assert(ps->pn);
proxy_negotiator_free(ps->pn);
ps->pn = NULL;
proxy_negotiator_cleanup(ps);
plug_log(ps->plug, PLUGLOG_CONNECT_SUCCESS, NULL, 0, NULL, 0);
@ -89,8 +100,7 @@ static void sk_proxy_close (Socket *s)
sk_close(ps->sub_socket);
sk_addr_free(ps->remote_addr);
if (ps->pn)
proxy_negotiator_free(ps->pn);
proxy_negotiator_cleanup(ps);
bufchain_clear(&ps->output_from_negotiator);
sfree(ps);
}
@ -191,6 +201,7 @@ static void plug_proxy_closing(Plug *p, PlugCloseType type,
{
ProxySocket *ps = container_of(p, ProxySocket, plugimpl);
proxy_negotiator_cleanup(ps);
plug_closing(ps->plug, type, error_msg);
}
@ -203,10 +214,12 @@ static void proxy_negotiate(ProxySocket *ps)
} else if (ps->pn->error) {
char *err = dupprintf("Proxy error: %s", ps->pn->error);
sfree(ps->pn->error);
proxy_negotiator_free(ps->pn);
ps->pn = NULL;
proxy_negotiator_cleanup(ps);
plug_closing_error(ps->plug, err);
sfree(err);
} else if (ps->pn->aborted) {
proxy_negotiator_cleanup(ps);
plug_closing_user_abort(ps->plug);
} else {
while (bufchain_size(&ps->output_from_negotiator)) {
ptrlen data = bufchain_prefix(&ps->output_from_negotiator);
@ -400,6 +413,53 @@ static const PlugVtable ProxySocket_plugvt = {
.accepting = plug_proxy_accepting
};
static char *proxy_description(Interactor *itr)
{
ProxySocket *ps = container_of(itr, ProxySocket, interactor);
assert(ps->pn);
return dupprintf("%s connection to %s port %d", ps->pn->vt->type,
conf_get_str(ps->conf, CONF_proxy_host),
conf_get_int(ps->conf, CONF_proxy_port));
}
static LogPolicy *proxy_logpolicy(Interactor *itr)
{
ProxySocket *ps = container_of(itr, ProxySocket, interactor);
return ps->clientlp;
}
static Seat *proxy_get_seat(Interactor *itr)
{
ProxySocket *ps = container_of(itr, ProxySocket, interactor);
return ps->clientseat;
}
static void proxy_set_seat(Interactor *itr, Seat *seat)
{
ProxySocket *ps = container_of(itr, ProxySocket, interactor);
ps->clientseat = seat;
}
static const InteractorVtable ProxySocket_interactorvt = {
.description = proxy_description,
.logpolicy = proxy_logpolicy,
.get_seat = proxy_get_seat,
.set_seat = proxy_set_seat,
};
static void proxy_prompts_callback(void *ctx)
{
proxy_negotiate((ProxySocket *)ctx);
}
prompts_t *proxy_new_prompts(ProxySocket *ps)
{
prompts_t *prs = new_prompts();
prs->callback = proxy_prompts_callback;
prs->callback_ctx = ps;
return prs;
}
Socket *new_connection(SockAddr *addr, const char *hostname,
int port, bool privport,
bool oobinline, bool nodelay, bool keepalive,
@ -429,6 +489,7 @@ Socket *new_connection(SockAddr *addr, const char *hostname,
ps = snew(ProxySocket);
ps->sock.vt = &ProxySocket_sockvt;
ps->plugimpl.vt = &ProxySocket_plugvt;
ps->interactor.vt = &ProxySocket_interactorvt;
ps->conf = conf_copy(conf);
ps->plug = plug;
ps->remote_addr = addr; /* will need to be freed on close */
@ -445,6 +506,17 @@ Socket *new_connection(SockAddr *addr, const char *hostname,
ps->sub_socket = NULL;
/*
* If we've been given an Interactor by the caller, set ourselves
* up to work with it.
*/
if (itr) {
ps->clientitr = itr;
interactor_set_child(ps->clientitr, &ps->interactor);
ps->clientlp = interactor_logpolicy(ps->clientitr);
ps->clientseat = interactor_borrow_seat(ps->clientitr);
}
const ProxyNegotiatorVT *vt;
switch (type) {
case PROXY_HTTP:
@ -467,7 +539,11 @@ Socket *new_connection(SockAddr *addr, const char *hostname,
ps->pn->ps = ps;
ps->pn->done = false;
ps->pn->error = NULL;
ps->pn->aborted = false;
ps->pn->input = &ps->pending_input_data;
/* Provide an Interactor to the negotiator if and only if we
* are usefully able to ask interactive questions of the user */
ps->pn->itr = ps->clientseat ? &ps->interactor : NULL;
bufchain_sink_init(ps->pn->output, &ps->output_from_negotiator);
{

View File

@ -38,8 +38,14 @@ struct ProxySocket {
/* configuration, used to look up proxy settings */
Conf *conf;
/* for interaction with the Seat */
Interactor *clientitr;
LogPolicy *clientlp;
Seat *clientseat;
Socket sock;
Plug plugimpl;
Interactor interactor;
};
struct ProxyNegotiator {
@ -50,6 +56,7 @@ struct ProxyNegotiator {
ProxySocket *ps;
bufchain *input;
bufchain_sink output[1];
Interactor *itr; /* NULL if we are not able to interact with the user */
/* Set to report success during proxy negotiation. */
bool done;
@ -58,6 +65,9 @@ struct ProxyNegotiator {
* ProxySocket will free it, and will then guarantee never to call
* process_queue again. */
char *error;
/* Set to report user abort during proxy negotiation. */
bool aborted;
};
struct ProxyNegotiatorVT {
@ -80,6 +90,12 @@ extern const ProxyNegotiatorVT socks4_proxy_negotiator_vt;
extern const ProxyNegotiatorVT socks5_proxy_negotiator_vt;
extern const ProxyNegotiatorVT telnet_proxy_negotiator_vt;
/*
* Centralised function to allow ProxyNegotiators to get hold of a
* prompts_t.
*/
prompts_t *proxy_new_prompts(ProxySocket *ps);
/*
* This may be reused by local-command proxies on individual
* platforms.