mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 09:27:59 +00:00
6c754822bc
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.
128 lines
3.8 KiB
C
128 lines
3.8 KiB
C
/*
|
|
* Network proxy abstraction in PuTTY
|
|
*
|
|
* A proxy layer, if necessary, wedges itself between the
|
|
* network code and the higher level backend.
|
|
*
|
|
* Supported proxies: HTTP CONNECT, generic telnet, SOCKS 4 & 5
|
|
*/
|
|
|
|
#ifndef PUTTY_PROXY_H
|
|
#define PUTTY_PROXY_H
|
|
|
|
typedef struct ProxySocket ProxySocket;
|
|
typedef struct ProxyNegotiator ProxyNegotiator;
|
|
typedef struct ProxyNegotiatorVT ProxyNegotiatorVT;
|
|
|
|
struct ProxySocket {
|
|
const char *error;
|
|
|
|
Socket *sub_socket;
|
|
Plug *plug;
|
|
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;
|
|
bool pending_eof;
|
|
|
|
bool freeze; /* should we freeze the underlying socket when
|
|
* we are done with the proxy negotiation? this
|
|
* simply caches the value of sk_set_frozen calls.
|
|
*/
|
|
|
|
ProxyNegotiator *pn; /* non-NULL if still negotiating */
|
|
bufchain output_from_negotiator;
|
|
|
|
/* 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 {
|
|
const ProxyNegotiatorVT *vt;
|
|
|
|
/* Standard fields for any ProxyNegotiator. new() and free() don't
|
|
* have to set these up; that's done centrally, to save duplication. */
|
|
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;
|
|
|
|
/* Set to report an error during proxy negotiation. The main
|
|
* 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;
|
|
|
|
/* 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 {
|
|
ProxyNegotiator *(*new)(const ProxyNegotiatorVT *);
|
|
void (*process_queue)(ProxyNegotiator *);
|
|
void (*free)(ProxyNegotiator *);
|
|
const char *type;
|
|
};
|
|
|
|
static inline ProxyNegotiator *proxy_negotiator_new(
|
|
const ProxyNegotiatorVT *vt)
|
|
{ return vt->new(vt); }
|
|
static inline void proxy_negotiator_process_queue(ProxyNegotiator *pn)
|
|
{ pn->vt->process_queue(pn); }
|
|
static inline void proxy_negotiator_free(ProxyNegotiator *pn)
|
|
{ pn->vt->free(pn); }
|
|
|
|
extern const ProxyNegotiatorVT http_proxy_negotiator_vt;
|
|
extern const ProxyNegotiatorVT socks4_proxy_negotiator_vt;
|
|
extern const ProxyNegotiatorVT socks5_proxy_negotiator_vt;
|
|
extern const ProxyNegotiatorVT telnet_proxy_negotiator_vt;
|
|
|
|
/*
|
|
* Centralised functions to allow ProxyNegotiators to get hold of a
|
|
* prompts_t, and to deal with SeatPromptResults coming back.
|
|
*/
|
|
prompts_t *proxy_new_prompts(ProxySocket *ps);
|
|
void proxy_spr_abort(ProxyNegotiator *pn, SeatPromptResult spr);
|
|
|
|
/*
|
|
* This may be reused by local-command proxies on individual
|
|
* platforms.
|
|
*/
|
|
#define TELNET_CMD_MISSING_USERNAME 0x0001
|
|
#define TELNET_CMD_MISSING_PASSWORD 0x0002
|
|
char *format_telnet_command(SockAddr *addr, int port, Conf *conf,
|
|
unsigned *flags_out);
|
|
|
|
DeferredSocketOpener *local_proxy_opener(
|
|
SockAddr *addr, int port, Plug *plug, Conf *conf, Interactor *itr);
|
|
void local_proxy_opener_set_socket(DeferredSocketOpener *opener,
|
|
Socket *socket);
|
|
char *platform_setup_local_proxy(Socket *socket, const char *cmd);
|
|
|
|
#include "cproxy.h"
|
|
|
|
#endif
|