mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38: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';
|
||||
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;
|
||||
|
@ -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.
|
||||
|
||||
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
|
||||
|
@ -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.
|
||||
|
||||
\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
|
||||
|
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_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];
|
||||
|
69
ssh.c
69
ssh.c
@ -729,6 +729,7 @@ struct ssh_tag {
|
||||
|
||||
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;
|
||||
@ -7622,7 +7623,59 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
||||
/*
|
||||
* 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);
|
||||
@ -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");
|
||||
} else
|
||||
ssh->mainchan = NULL;
|
||||
ssh->ncmode = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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),
|
||||
@ -7725,7 +7778,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
||||
/*
|
||||
* 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);
|
||||
@ -7751,7 +7804,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
||||
/*
|
||||
* 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 */
|
||||
@ -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.
|
||||
*/
|
||||
if (ssh->mainchan && *ssh->cfg.environmt) {
|
||||
if (ssh->mainchan && !ssh->ncmode && *ssh->cfg.environmt) {
|
||||
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.
|
||||
*/
|
||||
if (ssh->mainchan) while (1) {
|
||||
if (ssh->mainchan && !ssh->ncmode) while (1) {
|
||||
int subsys;
|
||||
char *cmd;
|
||||
|
||||
|
@ -813,7 +813,7 @@ int main(int argc, char **argv)
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -502,7 +502,7 @@ int main(int argc, char **argv)
|
||||
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;
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user