Files
kernel_Notes/Zim/Utils/ssh.txt~
2012-08-08 15:17:56 +08:00

88 lines
9.2 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-04-06T18:29:40+08:00
====== SSH tunnel tips ======
by pluskid, on 2009-08-14, in Tool 11 comments
http://blog.pluskid.org/?p=369
以前接触 SSH 的时候我就在文档上见过 SSH tunnel 相关的东西,然而当时没有怎么看明白,也就一直没有深究,直到最近需求越来越多了,才终于发现这个东西原来这么有用,于是记录在此。
** SSH tunnel** 主要有三种,一种是** dynamic application-level port forwarding **,可以用来作为 SOCKS proxy ,通常翻墙就是用的这种端口映射;一种是** Local Forwarding** ,主要用于提供常规的加密隧道,例如让 IMAP 协议通过这个加密隧道,避免密码在网络上被人监听到;一种是 **Remote Forwarding** ,可以用于逆向穿透 NAT 。其实,另外还有一种专门为 X 打造的 **X11 Forwarding** 一般不会用到Linux 下远程登录通常不会需要开启 X 程序,或者有其他更好用的方法,因此我们这里并不打算介绍这个。
首先我们来假定一个网络环境:有一个防火墙,在防火墙内部有一个机器 H ,通过 NAT 访问 Internet ,并且在防火墙外的 Internet 上的机器 T 上**有一个 ssh 帐号**,而另一台 Internet 上的机器 S 则是一台公共服务器,例如 Google 的服务器。如下图所示:
{{./ssh.png}}
ssh
首先来说 Local Forwarding ,相关的文档上都用的是阅读邮件这个经典的例子:用户在 T 上有一个 IMAP 服务器,本来他可以直接连接到 T:143 上阅读邮件的,但是这是未加密连接,如果你的 IMAP 服务器是用明文密码验证的方式的话,就很糟糕了,这样你的密码很容易被别人窃听到。这个时候 SSH 隧道就出来了,通过如下命令可以建立一个 SSH 隧道:
__ssh -L 9143:localhost:143 T__
#这里的local意思是本地的ssh客服端程序把由本地127.0.0.1:9143端口发出的数据通过与T间的ssh加密隧道转发到远程的143端口,由于指定了localhost故是T上的143端口。
首先不看参数,这个命令是发起一个 ssh 连接到主机 T ,然后选项 -L 表示 Local Forwarding **9143 表示本地(亦即 H的端口然后 localhost:143 则是远程(即 T上所对应的主机和端口**。这样一来,你在 H 上连接端口 9143 ,就相当于你在 T 上连接 localhost:143 一样SSH 建立的隧道会帮你在两个主机间传递信息。现在只要配置 H 上的邮件客户端去连接 localhost:9143 ,就能通过加密的方式访问到 T 上的 localhost:143 这个邮件服务器了。注意两个主机上的 localhost 的区别。
当然隧道并不限于 localhost(即远程的运行着sshd的服务器T) ,如果你愿意,可以做这样一个映射:
__ssh -L 9999:www.google.com:80 T__
#由于指定了www.google.com:本地的ssh客户端进程会把发往本地127.0.0.19999端口的数据通过加密隧道传给T然后T的sshd服务进程会把这个请求转发到www.google.com:80(sshd会根据传给他的应用层协议类型也就是目的端口号和IP或主机名来判断)并将返回的数据通过隧道传到H的127.0.0.19999端口。
这样,你可以在 H 的浏览器里输入 localhost:9999 访问到 Google 了。注意到 H 和 T 之间的数据传输是加密的,所以,如果 H 是处在伟大的局域网内,而 T 是在外部的话,可以通过这样的方法来访问 Google 而不受防火墙的限制。不过这种方法**每个端口只能映射一个网站**,很不方便。要用作代理通常还是使用 __dynamic application-level port__ forwarding 的方式,如下:
__ssh -D 9999 T__
#这时本地的ssh客户端进程担任了一个socks服务器的角色他监听本地的127.0.0.1:9999端口把从该端口发出的数据通过隧道传到T的sshd进程然后sshd再根据请求数据中的信息(IP地址或主机名加端口号)发送相应的请求然后把返回的数据通过隧道传给客户端的127.0.0.19999
这样建立起来的隧道实际上是一个 __SOCKS 代理__当然要使用 **SOCKS 代理需要客户端能够支持才行**,比如在 Firefox 中,只要在代理处填写 localhost:9999 并勾选 SOCKS5 代理即可。另外,还可以使用诸如 ProxyChains 之类的程序让本身不支持 SOCKS 代理的程序能够“透明地”使用 SOCKS 代理,不过我并没有尝试过,不知道稳定性如何。
最后要介绍的就是 Remote Forwarding 了,首先看命令吧:
__ssh -R 9923:10.13.21.88:23 T__
-R的意义是在远程主机T上指定一个sshd监听的端口号如9923然后他向该端口发的数据会通过隧道被H的ssh客户端接收然后ssh客户端会将请求数据转发给本地的主机和端口号。
这里 10.13.21.88 是 H 所在的局域网里的一台主机23 是 telnet 默认的端口,其实这就是浙大飘渺水云间 bbs 亦即“88”的校内地址了由于是在局域网内Internet 上的 T 是访问不到它的,现在 H 建立了一个到 T 的 Remote Forwarding ,对应之前的 Local Forwarding 的意思,应该能猜到了吧?现在在 T 上可以通过访问 localhost:9923 来上 88 了。 :D 换句话说,在 T 上访问 localhost:9923 相当于在 H 上访问 10.13.21.88:23 ,这成了一个反向的隧道。
综上Local 和Remote都是相对与本地H的ssh客服端进程来说的前者是将发往本地指定端口上的数据通过隧道发往sshd服务器sshd再做处理。
后者是本地的ssh客户进程将远程sshd传过来的数据(sshd监听并转发特定端口)转发到相应的主机。
另外,上面三种 Forwarding 默认建立的 socket 都是监听本机的 **loopback** 地址的这样外面的机器是不能访问这个端口映射的。对于最后那个飘渺水云间的隧道来讲默认情况下T 虽然可以通过 localhost:9923 来上 88 ,但是 S 却不能通过 T:9923 来访问到,而是会得到一个 Connection Refused 的错误这样做也是为了安全起见不过如果确实想要让__这个隧道可以从其他主机访问到的话__上面三个命令都可以在映射参数前面再加一个地址参数。例如飘渺水云间的那个映射其实等价于
ssh -R localhost:9923:10.13.21.88:23 T
把 localhost 改成 * 就可以让其他机器也访问到了(注意加上引号以防止 shell 把星号给展开了):
__ssh -R '*:9923:10.13.21.88:23' T__
唔,还有一点要说明的是,对于 -L 和 -D 来说,都是这样就可以了,而 -R 则还需要远程的 sshd 配置一下__ GatewayPorts __选项默认情况下是 no ,这样会无视掉客户端的请求,强制 bind 到 loopback 地址上,而 yes 则相当于强制 * ,如果设置成 clientspecified 则允许客户端来选择(注意,-R选项时的远程sshd监听的端口号是由ssh客户端在命令行上指定的)。因此在 /etc/ssh/sshd_config 文件里添加这样一行:
__GatewayPorts clientspecified__
再重启 ssh 服务即可。虽然学校提供了 RVPN 可以从校外访问到校内的资源,但是并没有提供 Linux 下的解决方案。在没有校外独立 IP 的情况下用这样的方法在外面访问学校的资源就变得非常有用了。要是 -D 也能有一个对应的 Reverse 的方案也许会更方便一些,不过也许可以用 -R 和 -D 桥接一个:
H$ ssh -D 9999 localhost
H$ ssh -R 9999:localhost:9999 T
在 T 上使用 localhost:9999 作为 SOCKS 代理,而该端口的数据会被 forward 到 H 上的 localhost:9999 ,那里是实际的 SOCKS 代理服务器。不过我没有实际测试过是不是真的可以用。 :p
最后再说一句,**FTP 是另一个经典的明文传输密码的协议,但是它却没法通过 SSH 隧道使用,因为它需要另外打开一个 socket 来传输数据**,这时就不在 SSH 的接管范围之内了,我想这也许是 SFTP 这个东西诞生的直接原因吧。其实使用了 -R 的端口映射之后,要 scp 回来是一件很容易的事,例如:
H$ ssh -R 9922:localhost:22 T
T$ scp foo.txt -P 9922 localhost:~/
可以将 T 上的 foo.txt 拷贝回 H 的主目录中。当然,如果只是为了做一个端口映射,可不必打开一个远程 shell ,只要再为 ssh 加上 -Nf 参数即可,具体是什么意思自己 man 吧。它会在后台运行,一直等待到对应隧道端口的连接。需要注意的是,在有了第一个连接之后,如果连接数降为零了,它会自动退出。所以我通常还是会打开远程 shell ,不过使用 screen 把它放在后台去,就不会妨碍了,需要的时候可以调出来,也可以方便地控制它什么时候退出。 :)
最后,在客户端的 ~/.ssh/config 里加入
ServerAliveInterval 180
这样可以防止长时间的 idle 导致 ssh 连接被自动断开。
不知道 iptables 做端口转发SSH 主要是做隧道了,要两台机器参与,端口转发的话是同一台机器双 IP 的情况吧?
关于用reversed tunneling做rvpn
往往情况是T也不是公网ip 例如在firewall后面
那H就不能ssh T了
结果是需要一个middlemanH,T都能访问到 那可以连上
可是谁能提供一个。。。