您的位置:首页 > 其它

ssh端口转发

2014-09-09 15:01 239 查看

ssh端口转发

2013-04-12 14:44:45| 分类: rhel_ssh|举报|字号 订阅

ssh的三个强大的端口转发命令:
ssh -C -f -N -g -L listen_port:DST_Host:DST_port user@Tunnel_Host
ssh -C -f -N -g -R listen_port:DST_Host:DST_port user@Tunnel_Host
ssh -C -f -N -g -D listen_port user@Tunnel_Host

-f Fork into background after authentication.
后台认证用户/密码,通常和-N连用,不用登录到远程主机。
-p port Connect to this port. Server must be on the same port.
被登录的ssd服务器的sshd服务端口。

-L port:host:hostport
本地机(客户机)的某个端口转发到远端指定机器的指定端口. 工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口,
一旦这个端口上有了连接, 该连接就经过安全通道转发出去, 同时远程主机和 host 的 hostport 端口建立连接.
可以在配置文件中指定端口的转发. 只有 root 才能转发特权端口. IPv6 地址用另一种格式说明: port/host/hostport

-R port:host:hostport
远程主机(服务器)的某个端口转发到本地端指定机器的指定端口. 工作原理是这样的, 远程主机上分配了一个 socket 侦听 port 端口,一旦这个端口上有了连接, 该连接就经过安全通道转向出去, 同时本地主机和 host 的 hostport 端口建立连接.
可以在配置文件中指定端口的转发. 只有用 root 登录远程主机才能转发特权端口. IPv6 地址用另一种格式说明:
port/host/hostport

-D port
指定一个本地机器 “动态的'’ 应用程序端口转发.
工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去,
根据应用程序的协议可以判断出远程主机将和哪里连接. 目前支持 SOCKS4 协议, 将充当 SOCKS4 服务器. 只有 root才能转发特权端口. 可以在配置文件中指定动态端口的转发.

-C Enable compression.
压缩数据传输。
-N Do not execute a shell or command.
不执行脚本或命令,通常与-f连用。
-g Allow remote hosts to connect to forwarded ports.
在-L/-R/-D参数中,允许远程主机连接到建立的转发的端口,如果不加这个参数,只允许本地主机建立连接。注:这个参数我在实践中似乎始终不起作用,参见III)
实例说明:
一台服务器提供ftp服务,因为ftp传输是明文密码,如果不做ssh端口之前,我们可以通过tcpdump命令很容易的捕捉到明文信息。所以我们要对21端口进行转发:
(ftp-server)# ssh -CNfg -R 2121:localhost:21 root@10.4.2.50
然后登录到10.4.2.50机器,我们可以通过netstat -an|grep :2121查看端口已经侦听
(10.4.2.50)# ftp localhost 21就可以登录到ftp-server了,而且tcpdump无法捕获到有效的信息。
2121端口任意选择,只要是机器上没有占用的端口就行

来一个稍微复杂一点的,做网关的例子:
例如内网有一台提供ftp(linux,port is 2121,称为A机器)的机器,通过网关服务器(linux,port is 8888,称为B机器)进去,现在外网有一台C机器需要访问网关服务器的某个端口(port is 21)来访问内网的ftp服务器。大家可以看到,其实这就像是一个基于ssh的防火墙程序,好,下面我们来具体操作:

1。login A 机器
# ssh -CNfg -R 8888:localhost:2121 root@B机器IP
这样我们就在B机器上开了一个8888->2121的端口转换,但是由于8888端口只能侦听在localhost主机上,因此,虽然我们已经可以在B机器上使用# ftp localhost 8888 来访问真正的ftp服务器,但仍然无法提供给外网的机器访问

2。login B机器
# ssh -CNfg -L 21:localhost:8888 root@localhost
这样做,是做本地机器上的21->8888端口转换,可以侦听在任何地址上的请求。
2(1)。
如果C机器也是一台linux机器,那也可以这样设置:
# ssh -CNfg -R 21:localhost:8888 root@C机器IP

3。使用C机器,可以是linux下的ftp命令,也可以是windows下的客户端软件都可以访问B机器的21端口来连接后台真正的ftp服务器(真正的端口是2121)

实际操作:

1.内网机器操作
ssh -CNfg -R 8880:localhost:8080 root@60.247.10.X

2.公网机器操作
ssh -CNfg -L 8881:localhost:8880 root@localhost

这样公网中的机器只需要访问http://60.247.10.X:8881

就访问到了我内网的那台部署tomcat的机器。

SSH原理与运用(二):远程操作与端口转发



(Image credit: Tony Narlock

七、远程操作

SSH不仅可以用于远程主机登录,还可以直接在远程主机上执行操作。

上一节的操作,就是一个例子:


  $ ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub


单引号中间的部分,表示在远程主机上执行的操作;后面的输入重定向,表示数据通过SSH传向远程主机。

这就是说,SSH可以在用户和远程主机之间,建立命令和数据的传输通道,因此很多事情都可以通过SSH来完成。

下面看几个例子。

【例1】

将$HOME/src/目录下面的所有文件,复制到远程主机的$HOME/src/目录。


  $ cd && tar czv src | ssh user@host 'tar xz'


【例2】

将远程主机$HOME/src/目录下面的所有文件,复制到用户的当前目录。


  $ ssh user@host 'tar cz src' | tar xzv


【例3】

查看远程主机是否运行进程httpd。


  $ ssh user@host 'ps ax | grep [h]ttpd'


八、绑定本地端口

既然SSH可以传送数据,那么我们可以让那些不加密的网络连接,全部改走SSH连接,从而提高安全性。

假定我们要让8080端口的数据,都通过SSH传向远程主机,命令就这样写:


  $ ssh -D 8080 user@host


SSH会建立一个socket,去监听本地的8080端口。一旦有数据传向那个端口,就自动把它转移到SSH连接上面,发往远程主机。可以想象,如果8080端口原来是一个不加密端口,现在将变成一个加密端口。

九、本地端口转发

有时,绑定本地端口还不够,还必须指定数据传送的目标主机,从而形成点对点的"端口转发"。为了区别后文的"远程端口转发",我们把这种情况称为"本地端口转发"(Local forwarding)。

假定host1是本地主机,host2是远程主机。由于种种原因,这两台主机之间无法连通。但是,另外还有一台host3,可以同时连通前面两台主机。因此,很自然的想法就是,通过host3,将host1连上host2。

我们在host1执行下面的命令:


  $ ssh -L 2121:host2:21 host3


命令中的L参数一共接受三个值,分别是"本地端口:目标主机:目标主机端口",它们之间用冒号分隔。这条命令的意思,就是指定SSH绑定本地端口2121,然后指定host3将所有的数据,转发到目标主机host2的21端口(假定host2运行FTP,默认端口为21)。

这样一来,我们只要连接host1的2121端口,就等于连上了host2的21端口。


  $ ftp localhost:2121


"本地端口转发"使得host1和host3之间仿佛形成一个数据传输的秘密隧道,因此又被称为"SSH隧道"。

十、远程端口转发

既然"本地端口转发"是指绑定本地端口的转发,那么"远程端口转发"(remote forwarding)当然是指绑定远程端口的转发。

还是接着看上面那个例子,host1与host2之间无法连通,必须借助host3转发。但是,特殊情况出现了,host3是一台内网机器,它可以连接外网的host1,但是反过来就不行,外网的host1连不上内网的host3。这时,"本地端口转发"就不能用了,怎么办?

解决办法是,既然host3可以连host1,那么就从host3上建立与host1的SSH连接,然后在host1上使用这条连接就可以了。

我们在host3执行下面的命令:


  $ ssh -R 2121:host2:21 host1


R参数也是接受三个值,分别是"远程主机端口:目标主机:目标主机端口"。这条命令的意思,就是让host1监听它自己的2121端口,然后将所有数据经由host3,转发到host2的21端口。由于对于host3来说,host1是远程主机,所以这种情况就被称为"远程端口绑定"。

绑定之后,我们在host1就可以连接host2了:


  $ ftp localhost:2121


这里必须指出,"远程端口转发"的前提条件是,host1和host3两台主机都有sshD和ssh客户端。

十一、SSH的其他参数

SSH还有一些别的参数,也值得介绍。

N参数,表示只连接远程主机,不打开远程shell;T参数,表示不为这个连接分配TTY。这个两个参数可以放在一起用,代表这个SSH连接只用来传数据,不执行远程操作。


  $ ssh -NT -D 8080 host


f参数,表示SSH连接成功后,转入后台运行。这样一来,你就可以在不中断SSH连接的情况下,在本地shell中执行其他操作。


  $ ssh -f -D 8080 host


要关闭这个后台连接,就只有用kill命令去杀掉进程。

十二、参考文献

  * SSH, The Secure Shell: The Definitive Guide: 2.4. Authentication by Cryptographic Key, O'reilly

  * SSH, The Secure Shell: The Definitive Guide: 9.2. Port Forwarding, O'reilly

  * Shebang: Tips for Remote Unix Work (SSH, screen, and VNC)

  * brihatch: SSH Host Key Protection

  * brihatch: SSH User Identities

  * IBM developerWorks: 实战 SSH 端口转发

  * Jianing YANG:ssh隧道技术简介

  * WikiBooks: Internet Technologies/SSH

昨天看到阮一峰先生两篇介绍ssh的文章:远程登录远程操作与端口转发,感觉很有意思。虽然我ssh一直在用,但也仅限于用其远程登录Linux。看了这两篇文章后我意识到原来ssh还有这么好玩的地方,我又孤陋寡闻了。于是在网上找了些ssh的资料大致研究了下,现在写这篇文章总结一下,以后看到新的东西也会持续修改这篇博文。本文只讨论ssh的常见用法,而不讨论其具体实现。

什么是ssh

ssh是Secure Shell的缩写,它是一个网络协议。ssh主要用来进行远程登录,数据传输,还有其他一些网络服务,同时这些操作都是建立在安全的信道之上的。ssh是通过公钥体系来保证安全性的,后面远程登录会讲到。需要注意的是ssh只是一种网络协议,它有不同的实现,其中openssh是其最广泛的实现,我们所使用的Linux上的ssh用的就是openssh。

远程登录

ssh最常用的功能就是远程登录计算机进行各种操作,因为在ssh远程登录计算机进行操作的整个过程中网络中传输的数据都是加密的,所以用ssh登录有相当的安全性。ssh远程登录主要有两种方式:通过密码登录,通过公钥登录。

密码登录

第一种方式是一种比较直观的方式,也是最常用的方式。它和我们一般的登录方式是一样的,即输入用户名及其密码进行登录。

如下shell命令:

?
1

ssh
user@
hostname


我们将登录的主机ip地址为hostname,使用该主机的账户user进行登录。接着会提示输入该用户的密码,输入正确后登录成功,就可以进行各种操作了。

但这种登录方式有一个缺点,它容易遭受中间人攻击。因为这种登录方式验证用户的方法是这样的:需要登录的一方将登录请求发给远程主机,远程主机收到登录请求后将自己的公钥发回来,在用户输入完密码后用传回的公钥加密这个密码,然后再将加密后的密码传给远程主机,远程主机用自己的私钥解密密码并进行验证,如果密码正确则说明该用户是合法的,允许登录。这里有一个漏洞,即攻击者可以冒充远程主机截获用户的登录请求,然后将自己伪造的公钥发给用户,以骗取用户的密码。在这种情况下用户是无法辨别此次登录的主机就是真正的主机。

为了避免这种情况,ssh在我们第一次登录一个主机时会有提醒,如下所示:

The authenticity of host '192.168.13.233 (192.168.13.233)' can't be established.
RSA key fingerprint is a9:97:4d:56:2f:77:f9:b7:1c:a9:d9:b9:a4:21:37:67.
Are you sure you want to continue connecting (yes/no)?

意思是ssh无法验证该远程主机,该主机公钥的指纹是a9:97:4d:56:2f:77:f9:b7:1c:a9:d9:b9:a4:21:37:67,这需要用户自己验证这个主机公钥的指纹是否真的是这个,如联系该主机管理员。如果用户确认无误,该远程主机的公钥就会保存在~/.ssh/known_hosts文件下,以后登录就可以直接判断该远程主机是合法的。

公钥登录

另一种登录方式可以不需要用户输入密码即可登录,而且比起密码登录更加安全。但是在用户登录远程主机之前需要一些额外的步骤。用户需要事先生成自己的公钥私钥对,通过某种手段将其生成的公钥放到远程主机上。该登录方式用户验证步骤如下:在用户登录远程主机的时候,远程主机获取已经存在本地的用户公钥,验证其合法性,如果合法就用该公钥加密一段随机字符串,然后将加密的内容传回用户,用户用自己对应的私钥进行解密,将解密之后的内容连同本次会话标示进行MD5,将该MD5值发给远程主机,远程主机收到后再进行同样的MD5比较它们是否一致,如果一致则说明目前用户是合法的。

可见这种登录方式稍微复杂一点。我们用如下命令生成密钥对:

?
1

ssh
-keygen -t rsa


这里会提示输入密码(passphrase),该密码会用来加密私钥,也可以直接回车不输入密码。成功之后会生成rsa的公钥和私钥对,公钥放在~/.ssh/id_rsa.pub文件中,私钥放在~/.ssh/id_rsa文件中。

而后要通过某种方法(如U盘拷贝,网络传输等)将id_rsa.pub中的内容追加到远程主机上相应用户~/.ssh/authorized_keys文件中,至此准备工作完成,用户登录的时候只需要输入下面的命令即可:

?
1

ssh
hostname


如果没有加密私钥则直接登录成功,否则需要输入加密私钥的密码。

端口转发

ssh另一大用处就是端口转发,这是我以前不了解的。所谓端口转发就是将本来发往某个目的地的数据包转发到其他的地址和端口上。其实这个是很常见的应用,包括外网要访问局域网内部的机器都要用到端口转发,只是我以前没注意到ssh也可以干这事。端口转发分为本地端口转发和远程端口转发两种,其实两者大同小异,只是ssh建立连接的方向不一样。为了以后方便讨论,现假设有三台主机A,B,C,主机名分别为hosta,hostb,hostc。

本地端口转发

本地转发中的本地是指将本地的某个端口转发到其他主机的某个端口,这样当我们的程序连接本地的这个端口时,其实间接连上了其他主机的某个端口,当我们发数据包到这个端口时数据包就自动转发到了那个远程端口上。本地端口转发的ssh命令格式如下:

ssh -L [bind_address:]port:host:hostport hostname

Linux manual解释如下:


Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and a connection is made to host port hostport from the remote machine. Port forwardings can also be specified in the configuration file. IPv6 addresses can be specified with an alternative syntax:[bind_address/]port/host/hostport or by enclosing the address in square brackets. Only the superuser can forward privileged ports. By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of “localhost” indicates that the listening port be bound for local use only, while an empty address or‘*’indicates that the port should be available from all interfaces.


可知运行上面命令后ssh会在本地主机监听端口port,如果有一个指向该端口的连接就将其转发的主机host的hostport端口上,hostname是用于转发的中间主机,它可以和host一样也可以不一样。

事实上,运行这条命令之后,本地主机的ssh客户端会连接上hostname主机上的ssh服务器端,通过这条链路将到本地端口的连接转发的host主机的hostport端口上。所以本地主机到hostname主机的通信是安全的,因为这两者是通过ssh连接的,然而从hostname到host的通信是不安全的,这点需要注意。另外本地端口绑定的地址是可选的,即可以指定该端口接收连接来自的网络接口,如果不指定则根据配置的GatewayPorts选项确定:如果该选项为yes则其他主机上程序可以连上该本地端口,否则只能使用回环接口,即只有本主机上的程序能连上该端口。如果指定了绑定地址则无视GatewayPorts选项。

例如我现在想将主机A的1132端口通过主机B转发主机C的21端口(ftp默认端口)上。要用本地端口转发在主机A上运行如下命令:

?
1A

ssh
-L 1132:hostc:21 hostb


这条命令之后所有发向主机A上1132端口的连接好像都变成了与主机C上21端口的连接。

同样地,我可以不通过中间主机B,而用ssh直接连上主机C进行端口转发,在主机A上运行如下命令:

?
1

ssh
-L 1132:hostc:21 hostc


这条命令和上一条效果是一样的,都是将端口转发到主机C,区别在ssh连接的是哪个主机。之所以

第一条命令要先连上主机B作为中转是因为在有些情况下主机A和主机C无法连通,而主机A和主机B可以连通,同时主机B可以和主机C相连,这时就可用ssh先连上主机B再通过其转发端口,这样我们就可以在无法连上主机C的情况下也可以使用主机C的ftp服务。

如下图所示,这种情况下主机A和主机B之间就形成了一条ssh隧道,在这条隧道中数据传输时加密的,所以不用担心传输内容被诸如防火墙之类的屏蔽。因此本地端口转发的一大用处就是在局域网内部通过建立一条到外网主机的ssh隧道,以此来访问被局域网网关屏蔽的外部服务。





远程端口转发

与本地端口转发相对的是远程端口转发。与本地转发不同,它指定的是远程主机的一个端口,将指向该端口的连接转发到本地端(不一定是本机)。可知远程转发和本地转发本质上是一样的,主要区别在于需要转发的端口是在远程主机上还是在本地主机上。远程端口转发ssh命令格式如下:

ssh -R [bind_address:]port:host:hostport hostname

Linux manual解释如下:


Specifies that the given port on the remote (server) host is to be forwarded to the given host and port on the local side. This works by allocating a socket to listen to port on the remote side, and whenever a connection is made to this port, the connection is forwarded over the secure channel, and a connection is made to host port hostport from the local machine.

Port forwardings can also be specified in the configuration file. Privileged ports can be forwarded only when logging in as root on the remote machine. IPv6 addresses can be specified by enclosing the address in square braces or using an alternative syntax:[bind_address/]host/port/hostport.

By default, the listening socket on the server will be bound to the loopback interface only. This may be overriden by specifying a bind_address. An empty bind_address, or the address‘*’, indicates that the remote socket should listen on all interfaces. Specifying a remote bind_address will only succeed if the server’s GatewayPorts option is enabled (see sshd_config(5)).


在这里要转发的端口port是在远程主机hostname上,将指向该端口的连接转发到本地端的主机host的hostport端口上,此时ssh会在远程主机hostname的port端口上监听到来的连接。同本地转发一样,这里也可以指定远程转发端口绑定的地址,但与本地转发不同的是只有在远程主机配置中将GatewayPorts 选项设为yes绑定的地址才有效,否则就算设置了绑定地址该端口也只会接收来自回环接口的连接。

比如我现在在主机A上想要将主机B的1132端口转发到本机的22端口(ssh默认端口)上,则在主机A上运行ssh命令如下:

?
1A

ssh
-R 1132:127.0.0.1:22 hostb


该命令执行之后主机A的ssh客户端向主机B的ssh服务器端建立一条连接,而后所有指向主机B上1132端口的连接都会转发到主机A的22端口,如下图所示。我现在可以在主机B上运行如下命令

?
1B

ssh
-p 1132 root@127.0.0.1


这样就相当于我远程登录了主机A,所以远程端口转发可以用来从外网访问局域网内部的服务。





ssh还有两个选项与上诉端口转发命令一起使用。

-N选项:指示当前ssh连接上服务器端之后不执行远程命令。

-f选项:指示当前ssh命令在后台执行。

SOCKS代理

上面介绍的端口转发都是两个特定的端口间的转发,如果我们想用同一个本地端口访问不同的外部服务怎么办?ssh对于这种情况也提供了解决方案,那就是将ssh作为SOCKS代理服务。SOCKS也是一种网络协议,它用于客户端和服务器之前数据传输的代理服务。ssh使用SOCKS服务的命令格式如下:

ssh –D [bind_address:]port hostname

Linux manual解释如下:


Specifies a local “dynamic” application-level port forwarding. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file.

IPv6 addresses can be specified with an alternative syntax:[bind_address/]port or by enclosing the address in square brackets. Only the superuser can forward privileged ports. By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of “localhost” indicates that the listening port be bound for local use only, while an empty address or‘*’indicates that the port should be available from all interfaces.


通过以上描述可知该命令相当于动态端口转发,将指向本地端口的连接转发到远程主机的端口上,而具体转发到哪里,是由上层的应用层协议决定的,目前ssh支持SOCKS4和SOCKS5两种协议。执行该命令后本机与hostname主机建立一条ssh连接用于中转SOCKS请求,这样所有启用SOCKS支持的本地程序都可以连接port端口,其连接将通过hostname主机转发到各自的目的地。同本地端口转发一样,本地用于转发的端口也可以绑定地址,如果不绑定则视GatewayPorts选项来决定是否接受其他主机的连接。

由于从本地到ssh服务器之间的数据传输是加密的,而且由于我国特殊的网络情况,所以ssh的这个功能常被用来突破网络封锁。例如如果我们有一个国外的ssh账号,就可以通过这种方法连接上国外的主机,然后启用浏览器的SOCKS代理使其指向本地的转发端口,由于本地和国外的这个主机传输内容是通过ssh加密的,这样就能躲过网络审查以浏览被屏蔽的内容。在Windows上的MyEntunnel等软件就是利用此原理穿墙的。

参考文献

1. SSH原理与运用(一):远程登录

2. SSH原理与运用(二):远程操作与端口转发

3. ssh公钥方式认证攻略

4. 实战 SSH 端口转发

5. SSH隧道技术简介

说实话,我对反向代理这个概念并不熟悉,只是感觉以下要做的事是一个代理的逆向过程,故借此名词一用。

问题场景是这样的:我有两套Linux集群的访问权限,分别为A和B,它们互相独立。其中A、B集群均能访问外网,但只有A集群有公网IP,所以从外网直接登录B就不行。要解决的问题就是从外网能登录到B集群。

我对代理的理解是:一台不能访问外网的机器,通过局域网内一台可以访问外网的机器代理服务,就能实现访问外网的目的。

而我以为的反向代理就是以上的逆向过程,这个肯定是可以做到的,比如:我们在外网要对某台局域网内的Windows进行远程桌面控制时就面临IP地址非公网的问题,但QQ能远程桌面却能完成这样的需求,区别就在于一个是被动受控,一个是主动请求受控;木马什么的,其实都是主动请求受控。

那么,在Linux集群之间,我该如何解决碰到的问题呢?以下是从http://portable.easylife.tw/entry/Reverse-SSH-Tunnel整理的部分内容,该内容正好能处理对应的需求。

通常用SSH Tunnel是用来完成类似代理的功能,如图:



红色区域可通过SSHTunnel访问原本受限的绿色部分,这一招通常用来FQ。

反向Tunnel可以解决我实际碰到的问题:



通过反向的Tunnel就可以做到了,具体步骤如下(以下内容转载而来,欢迎转载而去):

示例环境:

局域网主机:

ServerA / Linux / user userA / ip192.168.0.123 / ssh port 22

ServerB / Linux / user userB / ip192.168.0.125 / ssh port 22

PC / Windows / ip 192.168.0.128 / 远程桌面 port3389

远程主机:

MyServer / Linux / user me / ip 1.2.3.4 /ssh port 22

ssh参数:

-N:不执行何指令

-f:后台执行

-R:建立reverse tunnel

示例1:从MyServer ssh连回ServerA

[userA@ServerA] $ ssh -NfR 2222:localhost:22 me@MyServer

--------------------------------------------------------------

[me@MyServer] $ netstat -tnl | grep 127.0.0.1

tcp 0 0 127.0.0.1:2222 0.0.0.0:* LISTEN

[me@MyServer] $ ssh userA@127.0.0.1 -p 2222

MyServer连到2222 port会转向ServerA的ssh port,成功连接到ServerA

示例2:从MyServer ssh连回ServerB

[userA@ServerA] $ ssh -NfR 2244:192.168.0.125:22 me@MyServer

--------------------------------------------------------------

[me@MyServer] $ netstat -tnl | grep127.0.0.1

tcp 0 0 127.0.0.1:2244 0.0.0.0:* LISTEN

[me@MyServer] $ ssh userB@127.0.0.1 -p 2244

MyServer连接到本机的2244 port会转向 到ServerB的ssh port,成功连接到ServerB

示例3:从MyServer远程桌面PC

[userA@ServerA] $ ssh -NfR2266:192.168.0.128:3389 me@MyServer

--------------------------------------------------------------

[me@MyServer] $ netstat -tnl | grep127.0.0.1

tcp 0 0 127.0.0.1:2266 0.0.0.0:* LISTEN

[me@MyServer] $ rdesktop 127.0.0.1:2266

若你在Linux的桌面环境则可以直接display远程桌面PC,不然就export DISPLAY到其他主机。

此外,为了防止反向的Tunnel断开,还需要一个autossh工具,它可以帮助断线后自动重连。这个对我相当的重要,事实上我现在很少去B集群所在的地方。

对示例一做autossh可以如此做:

[userA@ServerA] $ autossh -M 12345-NfR2222:localhost:22 me@MyServer

当然,为了防止集群重启或断电等问题,可以将上语句写到开机启动脚本里。

以上的工作也可以通过putty完成,如示例3可以如下设置:



xshell也能干同样的事:



赶紧试试吧~~~~

今天看到个好东西,补充一下。

再上文中做反向隧道后,只能在本机ssh localhost -p 来登录,想要从其他IP来却不行,因为SSH本地端口转发绑定的是 lookback 接口。看网上博文http://blog.csdn.net/xyyangkun/article/details/7025854 说建立隧道时加-g参数可以实现,但我没有成功。不过看完https://www.ibm.com/developerworks/cn/linux/l-cn-sshforward/ 后灵机一动,再建立个本机公网到本机localhost的隧道就OK了:

ssh -g -L 9099:localhost:2222 localhost

这样就可以通过ssh 公网 -p 9099 来登录了!

一.本地端口转发
A机: 172.16.32.123
B机: 172.16.32.102, 10.0.0.2
C机: 10.0.0.1
(说明:C机与B机直连,C机无网关设置,只能与B机进行通信)

B机:(可以使用netstat -nap |grep 7001看到B机上启动了一个监听7001端口的服务)
luther@gliethttp:~$ ssh -CfNg -L 7001:localhost:22 luther@10.0.0.1

A机:(连接B机上的7001端口,因为B机将7001端口监听到的数据,直接转发给了C机,所以A将成功登录到C机)
luther@gliethttp:~$ ssh -p 7001 luther@172.16.32.102
这样A机就一下子连接到ip地址为10.0.0.1的C机了,实现了连接穿透.

让我们来仔细理解理解,A和C之间因不位于同一网段而不可见,B和A可见,B和C可见,
于是B就可以担当起转发A数据到C的角色.

连接图:A <=> B <==> C

ssh -L <local port>:<remote host>:<remote port> <SSH地址>

我们再来拆解一下语句:
1. B和C建立ssh连接
ssh luther@10.0.0.1
2. 参数-CfNg -L的解释
C - 压缩数据传输
f - 后台用户验证,允许没有shell的不可登陆账号使用
N - 不执行脚本或命令
g - 允许远程主机连接转发端口
L - 本地转发
3. 7001
表示ssh语句执行时,会同时在B机上由ssh命令自动开启一个监听B机上7001端口的service服务
4. :localhost:22
这个是最不易搞懂的地方,关键是这个参数是由谁来使用,当B机执行ssh的时候,C机上的ssh server
会接受B机的ssh连接,同时B机的参数:localhost:22被传递到C机的ssh server行,ssh server会解析
这个参数,C机上的ssh server会将B机ssh发送过来的数据,转发到<remote host>的<remote port>端口上.
可以使用如下实例验证:

===================================

a机: 172.16.32.102
b机: 172.16.32.123
c机: 172.16.32.112
d机: 172.16.32.54 测试机

只需要在b机上运行
luther@gliethttp:~$ ssh -CfNg -L 7001:172.16.32.112:22 (目标机 c) luther@172.16.32.102 (a机)

然后在d机上运行
luther@gliethttp:~$ ssh -p 7001 172.16.32.123 (b机)

数据流图:
d <=> b <=> a <=> c

d机连接b机7001端口,b机将d机发送的数据转发到a机的ssh server上,a机的ssh server根据
参数<remote host>:<remote port>即:172.16.32.112:22的定义,
将接收的数据进一步转发到<remote host>的<remote port>端口上,也就是172.16.32.112的22端口上,
所以d机最终和c机建立了ssh连接[luther.gliethttp]

二.远端端口转发
另一种ssh端口转发方式是使用参数-R,而不是-L.

ssh -R <local port>:<remote host>:<remote port> <SSH地址>
A机: 172.16.32.123
B机: 172.16.32.102, 10.0.0.2
C机: 10.0.0.1
(说明:C机与B机直连,C机无网关设置,只能与B机进行通信)

B机:运行如下命令
luther@gliethttp:~$ ssh -CfNg -R 7001:localhost:22 luther@10.0.0.1

C机:查看由C机上ssh server根据B机ssh连接的参数-R 7001创建的监听端口7001
我们在C机上使用netstat -nap |grep 7001看到C机上启动了一个监听7001端口的服务,
而C机上这个监听7001端口的服务是C机的ssh server根据B机执行ssh连接时的
参数-R 7001而由C机ssh server被动建立起来的.

同时C机上只能使用如下命令和C机自己身上的7001端口建立连接,不能使用ip地址,包括(10.0.0.1)
luther@gliethttp:~$ ssh -p 7001 luther@localhost
或者
luther@gliethttp:~$ ssh -p 7001 luther@127.0.0.1
以上2条命令使得C机可以ssh到B机.
另外也可以和上面-L一样,

B机:运行如下命令
luther@gliethttp:~$ ssh -CfNg -R 7001:172.16.32.123:22 luther@10.0.0.1
这时B机建立与C机的ssh,同时通知C机的ssh server,在C机上开启一个监听端口7001,
这样C机向C机本地的7001端口发送数据的时候,B机就能接收到,然后B机将根据
参数:172.16.32.123:22信息,将C机发送过来的数据转发到A机172.16.32.123的22端口

C机执行
ssh -p 7001 luther@localhost

就是等于向A机172.16.32.123的22端口发出ssh连接[luther.gliethttp]

三.比较本地端口转发-L和远端端口转发-R:
ssh -L <local port>:<remote host>:<remote port> <SSH地址>
ssh -R <local port>:<remote host>:<remote port> <SSH地址>
参数-L就是<local port>监听端口在执行ssh的机器上建立,参数<remote host>:<remote port>由<SSH地址>主机处理
参数-R就是<local port>监听端口在<SSH地址>主机上建立,参数<remote host>:<remote port>由执行ssh的机器处理

四.动态端口转发-D,设置SOCKS4和SOCKS5代理功能
B机: 172.16.32.102, 10.0.0.2
C机: 10.0.0.1
在C机上执行
ssh -CfNg -D 7001 luther@10.0.0.2
这样C机上将建立一个7001监听端口,C机可以向7001端口发送任何数据,然后B机10.0.0.2会将C机发送的数据
根据C机发送数据的端口号,动态的向外部递交,一般用在SOCKS代理,
C机的localhost:7001就是代理参数,可以在firefox上设置,这样C机就能通过B机上web网了.
到这里我们可以看出-L就是-D的一个具体实例使用,但是-D不能像-L一样,与指定的端口建立连接,所以-D使用在
SOCKS代理上[luther.gliethttp].
Firefox==>Edit==>Preferences==>Advanced
==>Network/Settings==>Manual proxy configuration
==>SOCKS Host: localhost
==>SOCKS Port: 7001
这样C机就能使用firefox上网了[luther.gliethttp]
(注意:因为C机的网关和DNS都没有设置,所以只能使用firefox中直接输入ip的方式上网,
比如www.google.com的ip地址为64.233.189.103).

五.X协议转发,实现ssh直接打开<SSH地址>主机上的GUI程序
A机(redhat): 172.16.32.102
B机(ubuntu): 172.16.32.123
首先A机进入桌面环境,打开一个terminal,
输入
luther@gliethttp:~$ ssh -X root@172.16.32.123 注意-X大写使能X11转发, -x小写禁用X11转发
但是缺点是只能查看,不能拖动拷贝到本机
[root@localhost ~]# firefox 执行远程机172.16.32.123上的firefox程序
[root@localhost ~]# nautilus / 执行远程机172.16.32.123上的nautilus文件浏览器

总结:
A机公司局域网
B机公网linux主机
C机家里的notebook
A机:
luther@gliethttp:~$ ssh -CfNg -R 7001:localhost:22 用户名@B机
C机:
luther@gliethttp:~$ ssh -CfNg -L 7000:localhost:7001 用户名@B机
C机:
luther@gliethttp:~$ ssh -p 7000 A机用户名@localhost 就可以登录公司的A机了
C机:
luther@gliethttp:~$ ssh -X -p 7000 A机用户名@localhost 就可以执行A机上的图形程序了,比如nautilus .

CentOS - 区别的ssh - X和运行startx

http://zh-cn.w3support.net/index.php?db=su&id=26356
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: