tags:

views:

396

answers:

8

When connecting to remote hosts via ssh, I frequently want to bring a file on that system to the local system for viewing or processing. Is there a way to copy the file over without (a) opening a new terminal/pausing the ssh session (b) authenticating again to either the local or remote hosts which works (c) even when one or both of the hosts is behind a NAT router?

The goal is to take advantage of as much of the current state as possible: that there is a connection between the two machines, that I'm authenticated on both, that I'm in the working directory of the file---so I don't have to open another terminal and copy and paste the remote host and path in, which is what I do now. The best solution also wouldn't require any setup before the session began, but if the setup was a one-time or able to be automated, than that's perfectly acceptable.

+1  A: 

Use the -M switch.

David Schmitt
A: 

You should be able to set up public & private keys so that no auth is needed.

Which way you do it depends on security requirements, etc (be aware that there are linux/unix ssh worms which will look at keys to find other hosts they can attack).

I do this all the time from behind both linksys and dlink routers. I think you may need to change a couple of settings but it's not a big deal.

chris
+1  A: 

In order to do this I have my home router set up to forward port 22 back to my home machine (which is firewalled to only accept ssh connections from my work machine) and I also have an account set up with DynDNS to provide Dynamic DNS that will resolve to my home IP automatically.

Then when I ssh into my work computer, the first thing I do is run a script that starts an ssh-agent (if your server doesn't do that automatically). The script I run is:

#!/bin/bash

ssh-agent sh -c 'ssh-add < /dev/null && bash'

It asks for my ssh key passphrase so that I don't have to type it in every time. You don't need that step if you use an ssh key without a passphrase.

For the rest of the session, sending files back to your home machine is as simple as

scp file_to_send.txt your.domain.name:~/
Ryan Ahearn
It would be nice if SCP / SFTP could be used across the already open SSH connection. Too bad to do so would involve a protocol change.
R. Bemrose
But with public key authentication, there isn't any great downside to opening a new SSH connection.
Ryan Ahearn
A: 

Here is a hack called ssh-xfer which addresses the exact problem, but requires patching OpenSSH, which is a nonstarter as far as I'm concerned.

Nick
+2  A: 

On a linux box I use the ssh-agent and sshfs. You need to setup the sshd to accept connections with key pairs. Then you use ssh-add to add you key to the ssh-agent so you don't have type your password everytime. Be sure to use -t seconds, so the key doesn't stay loaded forever.
ssh-add -t 3600 /home/user/.ssh/ssh_dsa

After that,
sshfs hostname:/ /PathToMountTo/
will mount the server file system on your machine so you have access to it.

Personally, I wrote a small bash script that add my key and mount the servers I use the most, so when I start to work I just have to launch the script and type my passphrase.

Eric Hogue
+3  A: 

zssh (a ZMODEM wrapper over openssh) does exactly what you want.

  • Install zssh and use it instead of openssh (which I assume that you normally use)

  • You'll have to have the lrzsz package installed on both systems.

Then, to transfer a file zyxel.png from remote to local host:

antti@local:~$ zssh remote
Press ^@ (C-Space) to enter file transfer mode, then ? for help
...
antti@remote:~$ sz zyxel.png
**B00000000000000
^@
zssh > rz
Receiving: zyxel.png
Bytes received:  104036/ 104036   BPS:16059729

Transfer complete
antti@remote:~$

Uploading goes similarly, except that you just switch rz(1) and sz(1).

Putty users can try Le Putty, which has similar functionality.

Antti Sykäri
A: 

Use the -M switch.

"Places the ssh client into 'master' mode for connection shar-ing. Multiple -M options places ssh into ``master'' mode with confirmation required before slave connections are accepted. Refer to the description of ControlMaster in ssh_config(5) for details."

I don't quite see how that answers the OP's question - can you expand on this a bit, David?

Flubba
This should probably be deleted and re-rendered as a comment. I am, however, with you: I don't get it.
dmckee
A: 

Here is my preferred solution to this problem. Set up a reverse ssh tunnel upon creating the ssh session. This is made easy by two bash function: grabfrom() needs to be defined on the local host, while grab() should be defined on the remote host. You can add any other ssh variables you use (e.g. -X or -Y) as you see fit.

function grabfrom() { ssh -R 2202:127.0.0.1:22 ${@}; };
function grab() { scp -P 2202 $@ [email protected]:~; };

Usage:

localhost% grabfrom remoteuser@remotehost
password: <remote password goes here>
remotehost% grab somefile1 somefile2 *.txt
password: <local password goes here>

Positives:

  • It works without special software on either host beyond OpenSSH
  • It works when local host is behind a NAT router
  • It can be implemented as a pair of two one-line bash function

Negatives:

  • It uses a fixed port number so:
    • won't work with multiple connections to remote host
    • might conflict with a process using that port on the remote host
  • It requires localhost accept ssh connections
  • It requires a special command on initiation the session
  • It doesn't implicitly handle authentication to the localhost
  • It doesn't allow one to specify the destination directory on localhost
  • If you grab from multiple localhosts to the same remote host, ssh won't like the keys changing

Future work: This is still pretty kludgy. Obviously, it would be possible to handle the authentication issue by setting up ssh keys appropriately and it's even easier to allow the specification of a remote directory by adding a parameter to grab()

More difficult is addressing the other negatives. It would be nice to pick a dynamic port but as far as I can tell there is no elegant way to pass that port to the shell on the remote host; As best as I can tell, OpenSSH doesn't allow you to set arbitrary environment variables on the remote host and bash can't take environment variables from a command line argument. Even if you could pick a dynamic port, there is no way to ensure it isn't used on the remote host without connecting first.

Nick