]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
New Plink operating mode: 'plink -shareexists'.
authorSimon Tatham <anakin@pobox.com>
Fri, 25 Sep 2015 10:46:28 +0000 (11:46 +0100)
committerSimon Tatham <anakin@pobox.com>
Fri, 25 Sep 2015 11:11:27 +0000 (12:11 +0100)
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.

13 files changed:
putty.h
raw.c
rlogin.c
ssh.c
ssh.h
sshshare.c
telnet.c
testback.c
unix/uxplink.c
unix/uxpty.c
unix/uxser.c
windows/winplink.c
windows/winser.c

diff --git a/putty.h b/putty.h
index cfdc81544a4efba4c353a3ce2f24a1ba185e7ee1..c854d9449ebd194e93054564dd26c50c2944afc5 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -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;
diff --git a/raw.c b/raw.c
index b083d09d59a572c885470b13911b26438b85722b..6262ed8994acc7a6a583addd71d924947ec11f3b 100644 (file)
--- a/raw.c
+++ b/raw.c
@@ -339,6 +339,7 @@ Backend raw_backend = {
     raw_provide_logctx,
     raw_unthrottle,
     raw_cfg_info,
+    NULL /* test_for_upstream */,
     "raw",
     PROT_RAW,
     0
index 10cda463ed81cf8d2c796130c9c91a0899dd3dc6..d73f7f9f97b7349025f1c566672178f5c63b5b7c 100644 (file)
--- a/rlogin.c
+++ b/rlogin.c
@@ -425,6 +425,7 @@ Backend rlogin_backend = {
     rlogin_provide_logctx,
     rlogin_unthrottle,
     rlogin_cfg_info,
+    NULL /* test_for_upstream */,
     "rlogin",
     PROT_RLOGIN,
     513
diff --git a/ssh.c b/ssh.c
index c93942361e9224658dc355b35ba70d6dcd27abdf..f3ce6fe0f5f4f3c1d5288df87987418c6e73b079 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -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
diff --git a/ssh.h b/ssh.h
index e8f1adad19b3b81f58cab284b3eda15af209ea03..75aad70ba82beddc788da304ef1c4250c6d6b1de 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -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);
index dcf805d6bf7d31e61c3beee9b8ebeb9d4983c7a9..6222003969fc6529ba04f283ff9a310e45c31ca5 100644 (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
index ca1665258c61429384135c619aa7c6989f270d91..0de8b016c381160ea3f627c171b623450e229b06 100644 (file)
--- a/telnet.c
+++ b/telnet.c
@@ -1129,6 +1129,7 @@ Backend telnet_backend = {
     telnet_provide_logctx,
     telnet_unthrottle,
     telnet_cfg_info,
+    NULL /* test_for_upstream */,
     "telnet",
     PROT_TELNET,
     23
index bf3047efd8bb51248e2f541d00de58994a3cba3b..752ec4ca03dc73eaa9d4a772f3b2a048837cba68 100644 (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 {
index 40b126615e31f3b3662a29ac8585ba2e4c100b84..ad122e9da4b3959f65a71f3824de1e7f3c86eb77 100644 (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.
      */
index 0b7c6309967fb908c8b74920cdd365b5c9191dd2..79a60f3c139c4fbc75517f9f9392c0d8a73db4be 100644 (file)
@@ -1218,6 +1218,7 @@ Backend pty_backend = {
     pty_provide_logctx,
     pty_unthrottle,
     pty_cfg_info,
+    NULL /* test_for_upstream */,
     "pty",
     -1,
     0
index 691e527ed143522470f7b1a45270a4170125adc2..41beaf0e75699866efe5f9080e572ad5f791df9d 100644 (file)
@@ -591,6 +591,7 @@ Backend serial_backend = {
     serial_provide_logctx,
     serial_unthrottle,
     serial_cfg_info,
+    NULL /* test_for_upstream */,
     "serial",
     PROT_SERIAL,
     0
index 43f53bb0426829891504e07b911b9b870b660fd0..8ffa4651030c9901b5a2f3d0923af1424f29b381 100644 (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.
      */
index 3f1326dba16badaabc4a4ca503b0d027f97dfa69..de9e61b480f91b6a9a5f6ccab81bf5142956f2bf 100644 (file)
@@ -453,6 +453,7 @@ Backend serial_backend = {
     serial_provide_logctx,
     serial_unthrottle,
     serial_cfg_info,
+    NULL /* test_for_upstream */,
     "serial",
     PROT_SERIAL,
     0