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

New Plink operating mode: 'plink -shareexists'.

A Plink invocation of the form 'plink -shareexists <session>' tests
for a currently live connection-sharing upstream for the session in
question. <session> can be any syntax you'd use with Plink to make the
actual connection (a host/port number, a bare saved session name,
-load, whatever).

I envisage this being useful for things like adaptive proxying - e.g.
if you want to connect to host A which you can't route to directly,
and you might already have a connection to either of hosts B or C
which are viable proxies, then you could write a proxy shell script
which checks whether you already have an upstream for B or C and goes
via whichever one is currently active.

Testing for the upstream's existence has to be done by actually
connecting to its socket, because on Unix the mere existence of a
Unix-domain socket file doesn't guarantee that there's a process
listening to it. So we make a test connection, and then immediately
disconnect; hence, that shows up in the upstream's event log.
This commit is contained in:
Simon Tatham 2015-09-25 11:46:28 +01:00
parent 14892997d6
commit 7c2ea22784
13 changed files with 107 additions and 2 deletions

View File

@ -445,6 +445,9 @@ struct backend_tag {
*/
void (*unthrottle) (void *handle, int);
int (*cfg_info) (void *handle);
/* Only implemented in the SSH protocol: check whether a
* connection-sharing upstream exists for a given configuration. */
int (*test_for_upstream)(const char *host, int port, Conf *conf);
const char *name;
int protocol;
int default_port;

1
raw.c
View File

@ -339,6 +339,7 @@ Backend raw_backend = {
raw_provide_logctx,
raw_unthrottle,
raw_cfg_info,
NULL /* test_for_upstream */,
"raw",
PROT_RAW,
0

View File

@ -425,6 +425,7 @@ Backend rlogin_backend = {
rlogin_provide_logctx,
rlogin_unthrottle,
rlogin_cfg_info,
NULL /* test_for_upstream */,
"rlogin",
PROT_RLOGIN,
513

14
ssh.c
View File

@ -3586,6 +3586,19 @@ static void ssh_hostport_setup(const char *host, int port, Conf *conf,
}
}
static int ssh_test_for_upstream(const char *host, int port, Conf *conf)
{
char *savedhost;
int savedport;
int ret;
ssh_hostport_setup(host, port, conf, &savedhost, &savedport, NULL);
ret = ssh_share_test_for_upstream(savedhost, savedport, conf);
sfree(savedhost);
return ret;
}
/*
* Connect to specified host and port.
* Returns an error message, or NULL on success.
@ -11645,6 +11658,7 @@ Backend ssh_backend = {
ssh_provide_logctx,
ssh_unthrottle,
ssh_cfg_info,
ssh_test_for_upstream,
"ssh",
PROT_SSH,
22

1
ssh.h
View File

@ -24,6 +24,7 @@ void sshfwd_x11_is_local(struct ssh_channel *c);
extern Socket ssh_connection_sharing_init(const char *host, int port,
Conf *conf, Ssh ssh, void **state);
int ssh_share_test_for_upstream(const char *host, int port, Conf *conf);
void share_got_pkt_from_server(void *ctx, int type,
unsigned char *pkt, int pktlen);
void share_activate(void *state, const char *server_verstring);

View File

@ -2027,6 +2027,55 @@ char *ssh_share_sockname(const char *host, int port, Conf *conf)
return sockname;
}
static void nullplug_socket_log(Plug plug, int type, SockAddr addr, int port,
const char *error_msg, int error_code) {}
static int nullplug_closing(Plug plug, const char *error_msg, int error_code,
int calling_back) { return 0; }
static int nullplug_receive(Plug plug, int urgent, char *data,
int len) { return 0; }
static void nullplug_sent(Plug plug, int bufsize) {}
int ssh_share_test_for_upstream(const char *host, int port, Conf *conf)
{
static const struct plug_function_table fn_table = {
nullplug_socket_log,
nullplug_closing,
nullplug_receive,
nullplug_sent,
NULL
};
struct nullplug {
const struct plug_function_table *fn;
} np;
char *sockname, *logtext, *ds_err, *us_err;
int result;
Socket sock;
np.fn = &fn_table;
sockname = ssh_share_sockname(host, port, conf);
sock = NULL;
logtext = ds_err = us_err = NULL;
result = platform_ssh_share(sockname, conf, (Plug)&np, (Plug)NULL, &sock,
&logtext, &ds_err, &us_err, FALSE, TRUE);
sfree(logtext);
sfree(ds_err);
sfree(us_err);
sfree(sockname);
if (result == SHARE_NONE) {
assert(sock == NULL);
return FALSE;
} else {
assert(result == SHARE_DOWNSTREAM);
sk_close(sock);
return TRUE;
}
}
/*
* Init function for connection sharing. We either open a listening
* socket and become an upstream, or connect to an existing one and

View File

@ -1129,6 +1129,7 @@ Backend telnet_backend = {
telnet_provide_logctx,
telnet_unthrottle,
telnet_cfg_info,
NULL /* test_for_upstream */,
"telnet",
PROT_TELNET,
23

View File

@ -58,14 +58,14 @@ Backend null_backend = {
null_init, null_free, null_reconfig, null_send, null_sendbuffer, null_size,
null_special, null_get_specials, null_connected, null_exitcode, null_sendok,
null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle,
null_cfg_info, "null", -1, 0
null_cfg_info, NULL /* test_for_upstream */, "null", -1, 0
};
Backend loop_backend = {
loop_init, loop_free, null_reconfig, loop_send, null_sendbuffer, null_size,
null_special, null_get_specials, null_connected, null_exitcode, null_sendok,
null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle,
null_cfg_info, "loop", -1, 0
null_cfg_info, NULL /* test_for_upstream */, "loop", -1, 0
};
struct loop_state {

View File

@ -607,6 +607,7 @@ int main(int argc, char **argv)
int errors;
int use_subsystem = 0;
int got_host = FALSE;
int just_test_share_exists = FALSE;
unsigned long now;
struct winsize size;
@ -685,6 +686,8 @@ int main(int argc, char **argv)
--argc;
provide_xrm_string(*++argv);
}
} else if (!strcmp(p, "-shareexists")) {
just_test_share_exists = TRUE;
} else {
fprintf(stderr, "plink: unknown option \"%s\"\n", p);
errors = 1;
@ -959,6 +962,19 @@ int main(int argc, char **argv)
!conf_get_str_nthstrkey(conf, CONF_portfwd, 0))
conf_set_int(conf, CONF_ssh_simple, TRUE);
if (just_test_share_exists) {
if (!back->test_for_upstream) {
fprintf(stderr, "Connection sharing not supported for connection "
"type '%s'\n", back->name);
return 1;
}
if (back->test_for_upstream(conf_get_str(conf, CONF_host),
conf_get_int(conf, CONF_port), conf))
return 0;
else
return 1;
}
/*
* Start up the connection.
*/

View File

@ -1218,6 +1218,7 @@ Backend pty_backend = {
pty_provide_logctx,
pty_unthrottle,
pty_cfg_info,
NULL /* test_for_upstream */,
"pty",
-1,
0

View File

@ -591,6 +591,7 @@ Backend serial_backend = {
serial_provide_logctx,
serial_unthrottle,
serial_cfg_info,
NULL /* test_for_upstream */,
"serial",
PROT_SERIAL,
0

View File

@ -303,6 +303,7 @@ int main(int argc, char **argv)
int errors;
int got_host = FALSE;
int use_subsystem = 0;
int just_test_share_exists = FALSE;
unsigned long now, next, then;
sklist = NULL;
@ -364,6 +365,8 @@ int main(int argc, char **argv)
} else if (!strcmp(p, "-pgpfp")) {
pgp_fingerprints();
exit(1);
} else if (!strcmp(p, "-shareexists")) {
just_test_share_exists = TRUE;
} else {
fprintf(stderr, "plink: unknown option \"%s\"\n", p);
errors = 1;
@ -596,6 +599,19 @@ int main(int argc, char **argv)
logctx = log_init(NULL, conf);
console_provide_logctx(logctx);
if (just_test_share_exists) {
if (!back->test_for_upstream) {
fprintf(stderr, "Connection sharing not supported for connection "
"type '%s'\n", back->name);
return 1;
}
if (back->test_for_upstream(conf_get_str(conf, CONF_host),
conf_get_int(conf, CONF_port), conf))
return 0;
else
return 1;
}
/*
* Start up the connection.
*/

View File

@ -453,6 +453,7 @@ Backend serial_backend = {
serial_provide_logctx,
serial_unthrottle,
serial_cfg_info,
NULL /* test_for_upstream */,
"serial",
PROT_SERIAL,
0