mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
New command-line option in Plink (and PuTTY, though it's less useful
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]
This commit is contained in:
parent
8c26b44ce6
commit
631b494807
22
cmdline.c
22
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';
|
cfg->portfwd[sizeof(cfg->portfwd) - 2] = '\0';
|
||||||
ptr[strlen(ptr)+1] = '\000'; /* append 2nd '\000' */
|
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")) {
|
if (!strcmp(p, "-m")) {
|
||||||
char *filename, *command;
|
char *filename, *command;
|
||||||
int cmdlen, cmdsize;
|
int cmdlen, cmdsize;
|
||||||
|
@ -1807,6 +1807,11 @@ output streams.
|
|||||||
This could be used, for instance, to talk to some kind of network proxy
|
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
|
that PuTTY does not natively support; or you could tunnel a connection
|
||||||
over something other than TCP/IP entirely.
|
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
|
||||||
|
@ -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
|
This option is not available in the file transfer tools PSCP and
|
||||||
PSFTP.
|
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}
|
\S2{using-cmdline-compress} \I{-C-upper}\c{-C}: enable \i{compression}
|
||||||
|
|
||||||
The \c{-C} option enables compression of the data sent across the
|
The \c{-C} option enables compression of the data sent across the
|
||||||
|
2
putty.h
2
putty.h
@ -458,6 +458,8 @@ struct config_tag {
|
|||||||
int ssh_subsys; /* run a subsystem rather than a command */
|
int ssh_subsys; /* run a subsystem rather than a command */
|
||||||
int ssh_subsys2; /* fallback to go with remote_cmd2 */
|
int ssh_subsys2; /* fallback to go with remote_cmd2 */
|
||||||
int ssh_no_shell; /* avoid running a shell */
|
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 */
|
/* Telnet options */
|
||||||
char termtype[32];
|
char termtype[32];
|
||||||
char termspeed[32];
|
char termspeed[32];
|
||||||
|
69
ssh.c
69
ssh.c
@ -729,6 +729,7 @@ struct ssh_tag {
|
|||||||
|
|
||||||
tree234 *channels; /* indexed by local id */
|
tree234 *channels; /* indexed by local id */
|
||||||
struct ssh_channel *mainchan; /* primary session channel */
|
struct ssh_channel *mainchan; /* primary session channel */
|
||||||
|
int ncmode; /* is primary channel direct-tcpip? */
|
||||||
int exitcode;
|
int exitcode;
|
||||||
int close_expected;
|
int close_expected;
|
||||||
int clean_exit;
|
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 = snew(struct ssh_channel);
|
||||||
ssh->mainchan->ssh = ssh;
|
ssh->mainchan->ssh = ssh;
|
||||||
ssh->mainchan->localid = alloc_channel_id(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);
|
add234(ssh->channels, ssh->mainchan);
|
||||||
update_specials_menu(ssh->frontend);
|
update_specials_menu(ssh->frontend);
|
||||||
logevent("Opened channel for session");
|
logevent("Opened channel for session");
|
||||||
} else
|
ssh->ncmode = FALSE;
|
||||||
ssh->mainchan = NULL;
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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];
|
char proto[20], data[64];
|
||||||
logevent("Requesting X11 forwarding");
|
logevent("Requesting X11 forwarding");
|
||||||
ssh->x11auth = x11_invent_auth(proto, sizeof(proto),
|
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");
|
logevent("Requesting OpenSSH-style agent forwarding");
|
||||||
s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
|
s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
|
||||||
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
|
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. */
|
/* Unpick the terminal-speed string. */
|
||||||
/* XXX perhaps we should allow no speeds to be sent. */
|
/* XXX perhaps we should allow no speeds to be sent. */
|
||||||
ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */
|
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
|
* Simplest thing here is to send all the requests at once, and
|
||||||
* then wait for a whole bunch of successes or failures.
|
* 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 *e = ssh->cfg.environmt;
|
||||||
char *var, *varend, *val;
|
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
|
* this twice if the config data has provided a second choice
|
||||||
* of command.
|
* of command.
|
||||||
*/
|
*/
|
||||||
if (ssh->mainchan) while (1) {
|
if (ssh->mainchan && !ssh->ncmode) while (1) {
|
||||||
int subsys;
|
int subsys;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user