通过ssh连接到远程主机时,我经常想将系统上的文件带到本地系统进行查看或处理。 有没有一种方法可以复制文件而无需(a)打开新终端/暂停ssh会话(b)再次向本地或远程主机进行身份验证,即使本地主机中的一个或两个都位于a后面,也可以正常工作(c) NAT路由器?
目标是尽可能多地利用当前状态:两台计算机之间存在连接,我在两台计算机上均已通过身份验证,并且我在文件的工作目录中-所以我 不必打开另一个终端并复制并粘贴远程主机和路径,这就是我现在要做的。 最好的解决方案也不需要在会话开始之前进行任何设置,但是如果设置是一次性的或能够自动化的,那将是完全可以接受的。
zssh(openssh上的ZMODEM包装器)完全可以满足您的需求。
然后,要将文件zyxel.webp从远程主机传输到本地主机:
1 2 3 4 5 6 7 8 9 10 11 12
| antti@local:~$ zssh remote
Press ^@ (C-Space) to enter file transfer mode, then ? for help
...
antti@remote:~$ sz zyxel.webp
**B00000000000000
^@
zssh > rz
Receiving: zyxel.webp
Bytes received: 104036/ 104036 BPS:16059729
Transfer complete
antti@remote:~$ |
上传的过程与此类似,只不过您只切换了rz(1)和sz(1)。
Putty用户可以尝试具有类似功能的Le Putty。
在Linux机器上,我使用ssh-agent和sshfs。您需要设置sshd以接受具有密钥对的连接。然后,您使用ssh-add将密钥添加到ssh-agent,这样就不必每次都键入密码。确保使用-t秒,这样密钥就不会永远保持加载状态。
ssh-add -t 3600 /home/user/.ssh/ssh_dsa
之后,
sshfs主机名:/ / PathToMountTo /
将服务器文件系统安装在您的计算机上,以便您可以访问它。
我个人编写了一个小的bash脚本,添加了我的密钥并挂载了我使用最多的服务器,因此,当我开始工作时,我只需要启动脚本并键入密码即可。
使用openssh的一些鲜为人知且很少使用的功能
实现您可以精确地完成您想要的!
-
利用当前状态
-
可以使用您所在的工作目录
-
在会话开始之前不需要任何隧道设置
-
不需要打开单独的端子或连接
-
可以用作交互式会话中的一次性交易,也可以用作自动会话的一部分
您应该只键入local>,remote>和
ssh>在以下示例中提示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| local> ssh username@remote
remote> ~C
ssh> -L6666:localhost:6666
remote> nc -l 6666 < /etc/passwd
remote> ~^Z
[suspend ssh]
[1]+ Stopped ssh username@remote
local> (sleep 1; nc localhost 6666 > /tmp/file) & fg
[2] 17357
ssh username@remote
remote> exit
[2]- Done ( sleep 1; nc localhost 6666 > /tmp/file )
local> cat /tmp/file
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
... |
或者,更常见的是您想走另一个方向,例如,如果您
想要执行类似的操作,例如从
您的本地计算机到远程计算机的~/.ssh/authorized_keys文件
机。
1 2 3 4 5 6 7 8 9 10 11 12 13
| local> ssh username@remote
remote> ~C
ssh> -R5555:localhost:5555
remote> ~^Z
[suspend ssh]
[1]+ Stopped ssh username@remote
local> nc -l 5555 < ~/.ssh/id_rsa.pub &
[2] 26607
local> fg
ssh username@remote
remote> nc localhost 5555 >> ~/.ssh/authorized_keys
remote> cat ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2ZQQQQBIwAAAQEAsgaVp8mnWVvpGKhfgwHTuOObyfYSe8iFvksH6BGWfMgy8poM2+5sTL6FHI7k0MXmfd7p4rzOL2R4q9yjG+Hl2PShjkjAVb32Ss5ZZ3BxHpk30+0HackAHVqPEJERvZvqC3W2s4aKU7ae4WaG1OqZHI1dGiJPJ1IgFF5bWbQl8CP9kZNAHg0NJZUCnJ73udZRYEWm5MEdTIz0+Q5tClzxvXtV4lZBo36Jo4vijKVEJ06MZu+e2WnCOqsfdayY7laiT0t/UsulLNJ1wT+Euejl+3Vft7N1/nWptJn3c4y83c4oHIrsLDTIiVvPjAj5JTkyH1EA2pIOxsKOjmg2Maz7Pw== username@local |
需要一点解释。
第一步是打开LocalForward;如果您还没有
建立后,您可以使用~C转义符打开一个
ssh命令行,它将为您提供以下命令:
1 2 3 4 5 6 7
| remote> ~C
ssh> help
Commands:
-L[bind_address:]port:host:hostport Request local forward
-R[bind_address:]port:host:hostport Request remote forward
-D[bind_address:]port Request dynamic forward
-KR[bind_address:]port Cancel remote forward |
在此示例中,我在本地主机的端口6666上建立了LocalForward
对于客户端和服务器;端口号可以是任何
任意开放的端口。
nc命令来自netcat包;它被描述为
" TCP / IP瑞士军刀";这是一个简单但非常灵活的方法
有用的程序。使它成为UNIX工具带的标准部分。
此时,nc正在侦听端口6666并等待另一个
程序以连接到该端口,以便它可以发送
/etc/passwd。
接下来,我们使用另一个转义字符~^Z,即tilde
跟control-Z。这会暂时中止ssh进程,并
让我们回到壳中
可以在本地系统上使用nc连接到
转发端口6666。请注意在这种情况下缺少-l,因为
选项告诉nc监听端口,就好像它是一台服务器一样。
不是我们想要的;相反,我们只想使用nc作为客户端
连接到远端已在监听的nc。
需要使用nc命令其余的魔术,因为如果
您还记得上面我说过的ssh进程是暂时的
暂停,因此&会将整个(sleep + nc)表达式
进入背景,sleep为您提供了足够的时间让ssh
用fg返回到前台。
在第二个示例中,除了我们设置
隧道使用-R而不是-l沿另一个方向移动,以便
我们建立一个RemoteForward。然后在本地方面
您要对nc使用-l参数。
默认情况下,转义字符是?,但是您可以使用以下命令更改该字符:
1 2 3 4
| -e escape_char
Sets the escape character for sessions with a pty (default: ‘~’). The escape character is only recognized at the beginning of a line. The escape character followed by a dot
(‘.’) closes the connection; followed by control-Z suspends the connection; and followed by itself sends the escape character once. Setting the character to"none" disables any
escapes and makes the session fully transparent. |
ssh联机帮助页中提供了转义字符可用命令的完整说明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| ESCAPE CHARACTERS
When a pseudo-terminal has been requested, ssh supports a number of functions through the use of an escape character.
A single tilde character can be sent as ~~ or by following the tilde by a character other than those described below. The escape character must always follow a newline to be interpreted
as special. The escape character can be changed in configuration files using the EscapeChar configuration directive or on the command line by the -e option.
The supported escapes (assuming the default ‘~’) are:
~. Disconnect.
~^Z Background ssh.
~# List forwarded connections.
~& Background ssh at logout when waiting for forwarded connection / X11 sessions to terminate.
~? Display a list of escape characters.
~B Send a BREAK to the remote system (only useful for SSH protocol version 2 and if the peer supports it).
~C Open command line. Currently this allows the addition of port forwardings using the -L, -R and -D options (see above). It also allows the cancellation of existing remote port-
forwardings using -KR[bind_address:]port. !command allows the user to execute a local command if the PermitLocalCommand option is enabled in ssh_config(5). Basic help is avail‐
able, using the -h option.
~R Request rekeying of the connection (only useful for SSH protocol version 2 and if the peer supports it). |
使用ControlMaster(-M开关)是最好的解决方案,比此处的其余答案更简单。它允许您在多个会话之间共享一个连接。听起来像海报所要的那样。但是,您仍然必须键入scp或sftp命令行。试试吧。我将其用于所有的活动。
最好的使用方法是,您可以通过HTTP公开文件,然后从另一台服务器下载文件,可以使用ZSSH Python库实现此目的,
ZSSH-SSH上的ZIP(简单的Python脚本,用于在服务器之间交换文件)。
使用PIP安装它。
1
| python3 -m pip install zssh |
从远程服务器运行此命令。
1
| python3 -m zssh -as --path /desktop/path_to_expose |
它将为您提供一个URL,以从另一台服务器执行。
在需要下载这些文件并解压缩的本地系统或其他服务器中。
1
| python3 -m zssh -ad --path /desktop/path_to_download --zip http://example.com/temp_file.zip |
有关此库的更多信息:https://pypi.org/project/zssh/
您可以使用SCP协议传输文件。可以参考此链接
http://tekheez.biz/scp-protocol-in-unix/
这是我针对此问题的首选解决方案。创建ssh会话后,设置反向ssh隧道。通过两个bash函数可以轻松实现这一点:grabfrom()需要在本地主机上定义,而grab()应该在远程主机上定义。您可以根据需要添加其他所有使用的ssh变量(例如-X或-Y)。
1 2
| function grabfrom() { ssh -R 2202:127.0.0.1:22 ${@}; };
function grab() { scp -P 2202 $@ localuser@127.0.0.1:~; }; |
用法:
1 2 3 4
| localhost% grabfrom remoteuser@remotehost
password: <remote password goes here>
remotehost% grab somefile1 somefile2 *.txt
password: <local password goes here> |
正面:
-
它可以在OpenSSH以外的任何主机上都无需特殊软件即可工作
-
当本地主机位于NAT路由器后面时,它可以工作
-
它可以实现为一对两个单行bash函数
负面因素:
-
它使用固定的端口号,因此:
-
无法与远程主机建立多个连接
-
可能与使用远程主机上的端口的进程冲突
-
它需要localhost接受ssh连接
-
在启动会话时需要特殊的命令
-
它不会隐式处理对本地主机的身份验证
-
它不允许在本地主机上指定目标目录
-
如果您从多个本地主机抓取到同一远程主机,则ssh不会喜欢更改密钥
未来的工作:
这仍然是个难题。显然,可以通过适当地设置ssh密钥来处理身份验证问题,并且通过向grab()添加参数来允许指定远程目录更加容易。
解决其他负面问题更加困难。选择一个动态端口会很好,但是据我所知,没有一种优雅的方法可以将该端口传递给远程主机上的shell。尽我所知,OpenSSH不允许您在远程主机上设置任意环境变量,bash不能从命令行参数获取环境变量。即使您可以选择一个动态端口,也无法确保没有先连接就不会在远程主机上使用它。
这是一个名为ssh-xfer的黑客,它可以解决确切的问题,但需要修补OpenSSH,就我而言,这是一个入门。
为此,我将家庭路由器设置为将端口22转发回我的家庭计算机(该防火墙已防火墙保护,仅接受来自我的工作计算机的ssh连接),并且我还为DynDNS设置了一个帐户来提供动态DNS,会自动解析为我的家庭IP。
然后,当我SSH进入工作计算机时,我要做的第一件事就是运行一个脚本,该脚本启动ssh-agent(如果您的服务器没有自动执行此操作)。我运行的脚本是:
1 2 3
| #!/bin/bash
ssh-agent sh -c 'ssh-add < /dev/null && bash' |
它要求输入我的ssh密钥密码,这样我就不必每次都键入它。如果您使用不带密码的ssh密钥,则无需执行该步骤。
在剩余的会话中,将文件发送回您的家用计算机非常简单
1
| scp file_to_send.txt your.domain.name:~/ |
使用-M开关。
"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."
blockquote>
我不太清楚这如何回答OP的问题-David,您可以谈谈吗?
您应该能够设置公钥和私钥,以便不需要身份验证。
采取哪种方式取决于安全性要求等(请注意,有些linux / unix ssh蠕虫会查看密钥以查找可以攻击的其他主机)。
我一直在从linksys和dlink路由器后面进行此操作。我认为您可能需要更改几个设置,但这没什么大不了的。