SSH端口转发的自我理解
三种模式:
ssh [-C] -f -N -g -L listen_port:DST_Host:DST_port user@Remote_Host
ssh [-C] -f -N -g -R listen_port:DST_Host:DST_port user@Remote_Host
ssh [-C] -f -N -g -D listen_port user@Remote_Host
三个角色:
本机
远程主机Remote_Host
目标主机DST_port
分别介绍三种模式:
1。L代表local,本地机器上分配了一个socket侦听listen_port端口, 一旦这个端口上有了连接, 本机就将该连接就经过安全通道转发出去到远程主机, 同时远程主机和DST_Host的DST_port端口建立tcp连接,DST_Host最好不要写localhost,即便是要转发到本机都一个端口,那么也最好要写本机的ip地址,因为我在实际测试时对于ssh2协议写localhost将不能正常工作.
2。R代表Remote,远程主机上分配了一个socket侦听listen_port端口, 一旦这个端口上有了连接, 远程主机就将该连接就经过安全通道转向出去到本机, 同时本地主机和DST_Host的DST_port端口建立tcp连接,DST_Host最好不要写localhost,即便是要转发到本机都一个端口,那么也最好要写本机的ip地址,因为我在实际测试时对于ssh2协议写localhost将不能正常工作.
3。D代表Dynamic,这个选项很nb的,只有它实现了应用程序级别的转发,而不局限在端口之间的转发(就是说该选项可以把你的请求放到隧道另一端执行,而不是简单的交给另一个端口背后的程序去处理),而且放置socket对于R和L模式来说只能是安全隧道的两端其一,而D模式则可以将socket放在任何一台能连得上的机器上。当socket上有连接时,直接通过隧道发到隧道的另一端,在隧道的另一端进行处理。比如访问youtube,假定A主机在国外,有BCD三个人,只有B能连上A,那么B就可以找个大家都能访问到的地方放置一个socket,然后大家通过这个socket去访问youtube就ok了,注意BCD在使用时需要在各自的浏览器里面设置一个sock4的代理服务器(其实就是socket的ip和port)。
实例说明:
一台服务器提供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 2121就可以登录到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:A机器IP:2121 root@B机器IP
这样我们就在B机器上开了一个B:8888->A:2121的端口转换,可以通过在B机器上执行netstat -nlpt来查看监听的8888端口的interface是哪个(一般会是0.0.0.0,这就表明这台机器的所有interface都在监听,如果是127.0.0.1,那就悲催了,只能在B机器上通过8888进行访问了,对于这种情况,可以考虑试试ssh -CNfg -R *:8888:A机器IP:2121 root@B机器IP看看,或者直接写0.0.0.0:8888或者B机器IP:8888,后来终于搞明白了,能否不只限于localhost,关键要看选项GatewayPorts是否为yes)。
2。login B机器
<1># ssh -CNfg -L 21:localhost:8888 root@localhost
这样做,是做本地机器上的B:21->B:8888端口转换,可以侦听在任何地址上的请求。
<2>如果C机器也是一台linux机器,那也可以这样设置:
# ssh -CNfg -R 21:localhost:8888 root@C机器IP,这样实现了C:21->B:8888的端口转换。
3。使用C机器,可以是linux下的ftp命令,也可以是windows下的客户端软件,如果按照<1>做的话,那么就可以访问B机器的21端口来连接后台真正的ftp服务器(真正的端口是2121);
如果是按照<2>中的设置,则访问的地址为本机IP。
............
N天之后又来接着写下面的实战体验:
前面分析的好复杂,现在有点实战经验了,哈哈,下面就给出大家最最常用到的三种应用场景,估计能满足一大篮子人,先声明一下:A->B代表A可以通过ssh连接B,注意这里只保证A能连接到B的一个端口(通常都是sshd的22端口),如果出现端口开放这种情况,那也不必打什么洞了,直接ssh连接好了,打洞不就为了能渗透进去嘛,呵呵;假定userA和ipA分别是用户名和机器ip地址。
A->B, 期望B->A, 解法: 在A上执行ssh -R 12345:localhost:22 userB@ipB -Nfg; 使用时在B上执行: ssh -p 12345 userA@localhost即可连接上A了;
B->A, B->C, 期望A->C(当然C->A也同理), 解法: 在B上执行ssh -R 12345:ipC:22 userA@ipA -Nfg; 使用时在A上执行: ssh -p 12345 userC@localhost即可连接上C了;
A->B, B->C, 期望A->C, 解法: 在A上执行ssh -L 12345:ipC:22 userB@ipB -Nfg; 使用时在A上执行ssh -p 12345 userC@localhost即可连接上C了.
把这三种应用玩熟了, 基本上就完全可以理解-R,-L,-D的奥妙了, 再玩出各种离奇的花样也就不在话下了. 而且我这里都是把proxy架设在A上了,对于A自身来讲,当A使用自身的proxy时自然就用localhost就ok了,如果D能连接到A上的12345端口,那么D能就做A期待的事情了(比如去连接C之类的).
B->A, B->C, C->D, 期望A->D, 端口转发的路径为A:12345->C:54321->D:22, 实现第一步转发需要在B上执行ssh -R 12345:ipC:54321 userA@ipA -Nfg; 实现第二步转发需要在C上执行ssh -D 54321 userD@ipD -Nfg. 但这么做需要机器C能够允许开放54321端口。
还有一种保守的解法如下:
B->A, B->C, C->D, 期望A->D, 我们可以先打通A->C, 问题就变成了A-C,
C->D, 期望A->D了, 然后再打通A->D即可, 实现A->C需要在B上执行ssh -R
12345:ipC:22 userA@ipA -Nfg; 实现A->D需要在A上执行ssh -p 12345 -L
54321:ipD:22 userC@localhost -Nfg; 接下来用ssh -p 54321 userD@localhost即可.
再告诉大家个好东西, 打通了之后, scp也能work了, 只是得用-P去指定端口而不是-p哟.
举个例子来说,比如要在本机再开一个端口30000用于ssh,那么可以: ssh -Nfg -L 本机IP地址:30000:本机IP地址:22 localhost
对于ssh2,应该这么写:ssh -q -g -f -L 本机IP地址:30000:本机IP地址:22 localhost
对于端口转发,还可以用iptable实现,参见:http://www.cyberciti.biz/faq/linux-port-redirection-with-iptables/
http://www.cyberciti.biz/faq/linux-port-redirection-with-iptables/
对于经常ssh的那些host,可以搞一些简单的alias分配给它们:
$ cat .ssh/config
Host pc1
Hostname 10.10.121.33
ssh -t admin@10.10.121.33 su test #在执行su test命令之前搞出个虚拟的tty
ssh -t 10.10.121.33 "su search -c 'ssh 10.10.121.34'"
ssh -o ProxyCommand='/usr/bin/nc -X connect -x 127.0.0.1:8087 %h %p' 10.10.121.33 #通过127.0.0.1:8087这个http代理来访问10.10.121.23, -X 5代表使用socks5代理
#下面三种方式完成的功能差不多
ssh -o ProxyCommand='ssh -q 10.10.121.34 nc %h %p' 10.10.121.33 #本地可以连上10.10.121.34,然后从10.10.121.34上借助于nc来连10.10.121.33
ssh -o ProxyCommand='ssh -q -W %h:%p 10.10.121.34' 10.10.121.33 #本地可以连上10.10.121.34,然后从10.10.121.34上可以连上10.10.121.33
ssh -t user@ServerA -p 1234 ssh -t user@ServerB -p 3456 ssh user@ServerC -p 5678 #先连ServerA,登录进ServerA之后再连ServerB,登录进ServerB之后再连ServerC
如果不想敲很长的命令行,可以写到config文件中:
vi ~/.ssh/config,并设定如下:
Host customer
Hostname customer.whatever.com
User linuxuser
ForwardAgent yes
Port 22
ProxyCommand ssh user1@jump.linux.com -p 5566 nc %h %p
Host db
Hostname db.whatever.com
User dbuser
ForwardAgent yes
Port 22
ProxyCommand ssh linuxuser@customer nc %h %p
Shell>$ ssh db
user@jump.linux.com's passoword:
linuxuser@customer.whatever.com's password:
linuxuser@db.whatever.com's password:
Last login: Tue Nov 9 01:05:05 2010 from 192.168.1.2
[linuxuser@db]$
参考资料:
http://www.perlmonks.org/?node_id=574891