]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
New command-line option in Plink (and PuTTY, though it's less useful
authorSimon Tatham <anakin@pobox.com>
Mon, 28 Aug 2006 15:12:37 +0000 (15:12 +0000)
committerSimon Tatham <anakin@pobox.com>
Mon, 28 Aug 2006 15:12:37 +0000 (15:12 +0000)
there): `plink host -nc host2:port' causes the SSH connection's main
channel to be replaced with a direct-tcpip connection to the
specified destination. This feature is mainly designed for use as a
local proxy: setting your local proxy command to `plink %proxyhost
-nc %host:%port' lets you tunnel SSH over SSH with a minimum of
fuss. Works on all platforms.

[originally from svn r6823]

cmdline.c
doc/config.but
doc/using.but
putty.h
ssh.c
unix/uxplink.c
windows/winplink.c

index e8343427b6100b1191ec824170136bbf76b3ee80..79f29816de83511b146ea89c9b435358c40e473e 100644 (file)
--- a/cmdline.c
+++ b/cmdline.c
@@ -249,6 +249,28 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg)
        cfg->portfwd[sizeof(cfg->portfwd) - 2] = '\0';
        ptr[strlen(ptr)+1] = '\000';    /* append 2nd '\000' */
     }
        cfg->portfwd[sizeof(cfg->portfwd) - 2] = '\0';
        ptr[strlen(ptr)+1] = '\000';    /* append 2nd '\000' */
     }
+    if ((!strcmp(p, "-nc"))) {
+       char *host, *portp;
+
+       RETURN(2);
+       UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
+       SAVEABLE(0);
+
+       host = portp = value;
+       while (*portp && *portp != ':')
+           portp++;
+       if (*portp) {
+           unsigned len = portp - host;
+           if (len >= sizeof(cfg->ssh_nc_host))
+               len = sizeof(cfg->ssh_nc_host) - 1;
+           strncpy(cfg->ssh_nc_host, value, len);
+           cfg->ssh_nc_host[sizeof(cfg->ssh_nc_host) - 1] = '\0';
+           cfg->ssh_nc_port = atoi(portp+1);
+       } else {
+           cmdline_error("-nc expects argument of form 'host:port'");
+           return ret;
+       }
+    }
     if (!strcmp(p, "-m")) {
        char *filename, *command;
        int cmdlen, cmdsize;
     if (!strcmp(p, "-m")) {
        char *filename, *command;
        int cmdlen, cmdsize;
index 42fa3aa0963734b9590091d6ffacba2156910b0f..e678db0559aeeb8d29cb02ce2ddd137a5a5f8064 100644 (file)
@@ -1807,6 +1807,11 @@ output streams.
 This could be used, for instance, to talk to some kind of network proxy
 that PuTTY does not natively support; or you could tunnel a connection
 over something other than TCP/IP entirely.
 This could be used, for instance, to talk to some kind of network proxy
 that PuTTY does not natively support; or you could tunnel a connection
 over something other than TCP/IP entirely.
+
+If you want your local proxy command to make a secondary SSH
+connection to a proxy host and then tunnel the primary connection
+over that, you might well want the \c{-nc} command-line option in
+Plink. See \k{using-cmdline-ncmode} for more information.
 }
 
 \S{config-proxy-exclude} Excluding parts of the network from proxying
 }
 
 \S{config-proxy-exclude} Excluding parts of the network from proxying
index 0fb7127b36e3edc476a5a8c853084d60541102fe..af98d9059edfef1291ce845565196ca6b3e00256 100644 (file)
@@ -796,6 +796,47 @@ at all} checkbox in the SSH panel of the PuTTY configuration box
 This option is not available in the file transfer tools PSCP and
 PSFTP.
 
 This option is not available in the file transfer tools PSCP and
 PSFTP.
 
+\S2{using-cmdline-ncmode} \I{-nc}\c{-nc}: make a \i{remote network
+connection} in place of a remote shell or command
+
+The \c{-nc} option prevents Plink (or PuTTY) from attempting to
+start a shell or command on the remote server. Instead, it will
+instruct the remote server to open a network connection to a host
+name and port number specified by you, and treat that network
+connection as if it were the main session.
+
+You specify a host and port as an argument to the \c{-nc} option,
+with a colon separating the host name from the port number, like
+this:
+
+\c plink host1.example.com -nc host2.example.com:1234
+
+You might want to use this feature if you needed to make an SSH
+connection to a target host which you can only reach by going
+through a proxy host, and rather than using port forwarding you
+prefer to use the local proxy feature (see \k{config-proxy-type} for
+more about local proxies). In this situation you might select
+\q{Local} proxy type, set your local proxy command to be \cq{plink
+%proxyhost -nc %host:%port}, enter the target host name on the
+Session panel, and enter the directly reachable proxy host name on
+the Proxy panel.
+
+This feature is only available in SSH protocol version 2 (since the
+version 1 protocol assumes you will always want to run a shell). It
+is not available in the file transfer tools PSCP and PSFTP. It is
+available in PuTTY itself, although it is unlikely to be very useful
+in any tool other than Plink. Also, \c{-nc} uses the same server
+functionality as port forwarding, so it will not work if your server
+administrator has disabled port forwarding.
+
+(The option is named \c{-nc} after the Unix program
+\W{http://www.vulnwatch.org/netcat/}\c{nc}, short for \q{netcat}.
+The command \cq{plink host1 -nc host2:port} is very similar in
+functionality to \cq{plink host1 nc host2 port}, which invokes
+\c{nc} on the server and tells it to connect to the specified
+destination. However, Plink's built-in \c{-nc} option does not
+depend on the \c{nc} program being installed on the server.)
+
 \S2{using-cmdline-compress} \I{-C-upper}\c{-C}: enable \i{compression}
 
 The \c{-C} option enables compression of the data sent across the
 \S2{using-cmdline-compress} \I{-C-upper}\c{-C}: enable \i{compression}
 
 The \c{-C} option enables compression of the data sent across the
diff --git a/putty.h b/putty.h
index 22ec8259c40ef63337ef7926b55c6f69d35b4223..c648921bc30037511c45ecb28c81bf673a970d3d 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -458,6 +458,8 @@ struct config_tag {
     int ssh_subsys;                   /* run a subsystem rather than a command */
     int ssh_subsys2;                  /* fallback to go with remote_cmd2 */
     int ssh_no_shell;                 /* avoid running a shell */
     int ssh_subsys;                   /* run a subsystem rather than a command */
     int ssh_subsys2;                  /* fallback to go with remote_cmd2 */
     int ssh_no_shell;                 /* avoid running a shell */
+    char ssh_nc_host[512];            /* host to connect to in `nc' mode */
+    int ssh_nc_port;                  /* port to connect to in `nc' mode */
     /* Telnet options */
     char termtype[32];
     char termspeed[32];
     /* Telnet options */
     char termtype[32];
     char termspeed[32];
diff --git a/ssh.c b/ssh.c
index 7c5c7bce91b2e9e97a16327b2827231c6419eb2e..6380b09d21e0429a9318b795ba9f925dd818cb7b 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -729,6 +729,7 @@ struct ssh_tag {
 
     tree234 *channels;                /* indexed by local id */
     struct ssh_channel *mainchan;      /* primary session channel */
 
     tree234 *channels;                /* indexed by local id */
     struct ssh_channel *mainchan;      /* primary session channel */
+    int ncmode;                               /* is primary channel direct-tcpip? */
     int exitcode;
     int close_expected;
     int clean_exit;
     int exitcode;
     int close_expected;
     int clean_exit;
@@ -7622,7 +7623,59 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
     /*
      * Create the main session channel.
      */
     /*
      * Create the main session channel.
      */
-    if (!ssh->cfg.ssh_no_shell) {
+    if (ssh->cfg.ssh_no_shell) {
+       ssh->mainchan = NULL;
+    } else if (*ssh->cfg.ssh_nc_host) {
+       /*
+        * Just start a direct-tcpip channel and use it as the main
+        * channel.
+        */
+       ssh->mainchan = snew(struct ssh_channel);
+       ssh->mainchan->ssh = ssh;
+       ssh->mainchan->localid = alloc_channel_id(ssh);
+       s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
+       ssh2_pkt_addstring(s->pktout, "direct-tcpip");
+       ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);
+       ssh->mainchan->v.v2.locwindow = OUR_V2_WINSIZE;
+       ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */
+       ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT);      /* our max pkt size */
+       ssh2_pkt_addstring(s->pktout, ssh->cfg.ssh_nc_host);
+       ssh2_pkt_adduint32(s->pktout, ssh->cfg.ssh_nc_port);
+       /*
+        * We make up values for the originator data; partly it's
+        * too much hassle to keep track, and partly I'm not
+        * convinced the server should be told details like that
+        * about my local network configuration.
+        * The "originator IP address" is syntactically a numeric
+        * IP address, and some servers (e.g., Tectia) get upset
+        * if it doesn't match this syntax.
+        */
+       ssh2_pkt_addstring(s->pktout, "0.0.0.0");
+       ssh2_pkt_adduint32(s->pktout, 0);
+       ssh2_pkt_send(ssh, s->pktout);
+
+       crWaitUntilV(pktin);
+       if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
+           bombout(("Server refused to open a direct-tcpip channel"));
+           crStopV;
+           /* FIXME: error data comes back in FAILURE packet */
+       }
+       if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) {
+           bombout(("Server's channel confirmation cited wrong channel"));
+           crStopV;
+       }
+       ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);
+       ssh->mainchan->halfopen = FALSE;
+       ssh->mainchan->type = CHAN_MAINSESSION;
+       ssh->mainchan->closes = 0;
+       ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);
+       ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
+       bufchain_init(&ssh->mainchan->v.v2.outbuffer);
+       add234(ssh->channels, ssh->mainchan);
+       update_specials_menu(ssh->frontend);
+       logevent("Opened direct-tcpip channel in place of session");
+       ssh->ncmode = TRUE;
+    } else {
        ssh->mainchan = snew(struct ssh_channel);
        ssh->mainchan->ssh = ssh;
        ssh->mainchan->localid = alloc_channel_id(ssh);
        ssh->mainchan = snew(struct ssh_channel);
        ssh->mainchan->ssh = ssh;
        ssh->mainchan->localid = alloc_channel_id(ssh);
@@ -7653,8 +7706,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
        add234(ssh->channels, ssh->mainchan);
        update_specials_menu(ssh->frontend);
        logevent("Opened channel for session");
        add234(ssh->channels, ssh->mainchan);
        update_specials_menu(ssh->frontend);
        logevent("Opened channel for session");
-    } else
-       ssh->mainchan = NULL;
+       ssh->ncmode = FALSE;
+    }
 
     /*
      * Now we have a channel, make dispatch table entries for
 
     /*
      * Now we have a channel, make dispatch table entries for
@@ -7677,7 +7730,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
     /*
      * Potentially enable X11 forwarding.
      */
     /*
      * Potentially enable X11 forwarding.
      */
-    if (ssh->mainchan && ssh->cfg.x11_forward) {
+    if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward) {
        char proto[20], data[64];
        logevent("Requesting X11 forwarding");
        ssh->x11auth = x11_invent_auth(proto, sizeof(proto),
        char proto[20], data[64];
        logevent("Requesting X11 forwarding");
        ssh->x11auth = x11_invent_auth(proto, sizeof(proto),
@@ -7725,7 +7778,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
     /*
      * Potentially enable agent forwarding.
      */
     /*
      * Potentially enable agent forwarding.
      */
-    if (ssh->mainchan && ssh->cfg.agentfwd && agent_exists()) {
+    if (ssh->mainchan && !ssh->ncmode && ssh->cfg.agentfwd && agent_exists()) {
        logevent("Requesting OpenSSH-style agent forwarding");
        s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
        ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
        logevent("Requesting OpenSSH-style agent forwarding");
        s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
        ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
@@ -7751,7 +7804,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
     /*
      * Now allocate a pty for the session.
      */
     /*
      * Now allocate a pty for the session.
      */
-    if (ssh->mainchan && !ssh->cfg.nopty) {
+    if (ssh->mainchan && !ssh->ncmode && !ssh->cfg.nopty) {
        /* Unpick the terminal-speed string. */
        /* XXX perhaps we should allow no speeds to be sent. */
         ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */
        /* Unpick the terminal-speed string. */
        /* XXX perhaps we should allow no speeds to be sent. */
         ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */
@@ -7801,7 +7854,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
      * Simplest thing here is to send all the requests at once, and
      * then wait for a whole bunch of successes or failures.
      */
      * Simplest thing here is to send all the requests at once, and
      * then wait for a whole bunch of successes or failures.
      */
-    if (ssh->mainchan && *ssh->cfg.environmt) {
+    if (ssh->mainchan && !ssh->ncmode && *ssh->cfg.environmt) {
        char *e = ssh->cfg.environmt;
        char *var, *varend, *val;
 
        char *e = ssh->cfg.environmt;
        char *var, *varend, *val;
 
@@ -7866,7 +7919,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
      * this twice if the config data has provided a second choice
      * of command.
      */
      * this twice if the config data has provided a second choice
      * of command.
      */
-    if (ssh->mainchan) while (1) {
+    if (ssh->mainchan && !ssh->ncmode) while (1) {
        int subsys;
        char *cmd;
 
        int subsys;
        char *cmd;
 
index 38129f968b0e637ada6c36bb3a5a0e1c57b00b8f..1d3db4c26f253f8b82bc31d4725b176180e9c403 100644 (file)
@@ -813,7 +813,7 @@ int main(int argc, char **argv)
        cfg.host[p1] = '\0';
     }
 
        cfg.host[p1] = '\0';
     }
 
-    if (!cfg.remote_cmd_ptr && !*cfg.remote_cmd)
+    if (!cfg.remote_cmd_ptr && !*cfg.remote_cmd && !*cfg.ssh_nc_host)
        flags |= FLAG_INTERACTIVE;
 
     /*
        flags |= FLAG_INTERACTIVE;
 
     /*
index 562d26af83ec685e8d5976aa53218294348e4e95..c79c1e5dd46c03f03746204bf5b5fa78e3e18a14 100644 (file)
@@ -502,7 +502,7 @@ int main(int argc, char **argv)
        cfg.host[p1] = '\0';
     }
 
        cfg.host[p1] = '\0';
     }
 
-    if (!cfg.remote_cmd_ptr && !*cfg.remote_cmd)
+    if (!cfg.remote_cmd_ptr && !*cfg.remote_cmd && !*cfg.ssh_nc_host)
        flags |= FLAG_INTERACTIVE;
 
     /*
        flags |= FLAG_INTERACTIVE;
 
     /*