SSH端口轉(zhuǎn)發(fā)的自我理解
三種模式:
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
三個(gè)角色:
本機(jī)
遠(yuǎn)程主機(jī)Remote_Host
目標(biāo)主機(jī)DST_port
分別介紹三種模式:
1。L代表local,本地機(jī)器上分配了一個(gè)socket偵聽listen_port端口, 一旦這個(gè)端口上有了連接, 本機(jī)就將該連接就經(jīng)過安全通道轉(zhuǎn)發(fā)出去到遠(yuǎn)程主機(jī), 同時(shí)遠(yuǎn)程主機(jī)和DST_Host的DST_port端口建立tcp連接,DST_Host最好不要寫localhost,即便是要轉(zhuǎn)發(fā)到本機(jī)都一個(gè)端口,那么也最好要寫本機(jī)的ip地址,因?yàn)槲以趯?shí)際測試時(shí)對于ssh2協(xié)議寫localhost將不能正常工作.
2。R代表Remote,遠(yuǎn)程主機(jī)上分配了一個(gè)socket偵聽listen_port端口, 一旦這個(gè)端口上有了連接, 遠(yuǎn)程主機(jī)就將該連接就經(jīng)過安全通道轉(zhuǎn)向出去到本機(jī), 同時(shí)本地主機(jī)和DST_Host的DST_port端口建立tcp連接,DST_Host最好不要寫localhost,即便是要轉(zhuǎn)發(fā)到本機(jī)都一個(gè)端口,那么也最好要寫本機(jī)的ip地址,因?yàn)槲以趯?shí)際測試時(shí)對于ssh2協(xié)議寫localhost將不能正常工作.
3。D代表Dynamic,這個(gè)選項(xiàng)很nb的,只有它實(shí)現(xiàn)了應(yīng)用程序級別的轉(zhuǎn)發(fā),而不局限在端口之間的轉(zhuǎn)發(fā)(就是說該選項(xiàng)可以把你的請求放到隧道另一端執(zhí)行,而不是簡單的交給另一個(gè)端口背后的程序去處理),而且放置socket對于R和L模式來說只能是安全隧道的兩端其一,而D模式則可以將socket放在任何一臺能連得上的機(jī)器上。當(dāng)socket上有連接時(shí),直接通過隧道發(fā)到隧道的另一端,在隧道的另一端進(jìn)行處理。比如訪問youtube,假定A主機(jī)在國外,有BCD三個(gè)人,只有B能連上A,那么B就可以找個(gè)大家都能訪問到的地方放置一個(gè)socket,然后大家通過這個(gè)socket去訪問youtube就ok了,注意BCD在使用時(shí)需要在各自的瀏覽器里面設(shè)置一個(gè)sock4的代理服務(wù)器(其實(shí)就是socket的ip和port)。
實(shí)例說明:
一臺服務(wù)器提供ftp服務(wù),因?yàn)閒tp傳輸是明文密碼,如果不做ssh端口之前,我們可以通過tcpdump命令很容易的捕捉到明文信息。所以我們要對21端口進(jìn)行轉(zhuǎn)發(fā):
(ftp-server)# ssh -CNfg -R 2121:localhost:21 root@10.4.2.50
然后登錄到10.4.2.50機(jī)器,我們可以通過netstat -an|grep :2121查看端口已經(jīng)偵聽
(10.4.2.50)# ftp localhost 2121就可以登錄到ftp-server了,而且tcpdump無法捕獲到有效的信息。
2121端口任意選擇,只要是機(jī)器上沒有占用的端口就行。
來一個(gè)稍微復(fù)雜一點(diǎn)的,做網(wǎng)關(guān)的例子:
假如內(nèi)網(wǎng)有一臺提供ftp(linux,port is 2121,稱為A機(jī)器)的機(jī)器,通過網(wǎng)關(guān)服務(wù)器(linux,port is 8888,稱為B機(jī)器)進(jìn)去,現(xiàn)在外網(wǎng)有一臺C機(jī)器需要訪問網(wǎng)關(guān)服務(wù)器的某個(gè)端口(port is 21)來訪問內(nèi)網(wǎng)的ftp服務(wù)器。大家可以看到,其實(shí)這就像是一個(gè)基于ssh的防火墻程序,好,下面我們來具體操作:
1。login A 機(jī)器
# ssh -CNfg -R 8888:A機(jī)器IP:2121 root@B機(jī)器IP
這樣我們就在B機(jī)器上開了一個(gè)B:8888->A:2121的端口轉(zhuǎn)換,可以通過在B機(jī)器上執(zhí)行netstat -nlpt來查看監(jiān)聽的8888端口的interface是哪個(gè)(一般會是0.0.0.0,這就表明這臺機(jī)器的所有interface都在監(jiān)聽,如果是127.0.0.1,那就悲催了,只能在B機(jī)器上通過8888進(jìn)行訪問了,對于這種情況,可以考慮試試ssh -CNfg -R *:8888:A機(jī)器IP:2121 root@B機(jī)器IP看看,或者直接寫0.0.0.0:8888或者B機(jī)器IP:8888,后來終于搞明白了,能否不只限于localhost,關(guān)鍵要看選項(xiàng)GatewayPorts是否為yes)。
2。login B機(jī)器
<1># ssh -CNfg -L 21:localhost:8888 root@localhost
這樣做,是做本地機(jī)器上的B:21->B:8888端口轉(zhuǎn)換,可以偵聽在任何地址上的請求。
<2>如果C機(jī)器也是一臺linux機(jī)器,那也可以這樣設(shè)置:
# ssh -CNfg -R 21:localhost:8888 root@C機(jī)器IP,這樣實(shí)現(xiàn)了C:21->B:8888的端口轉(zhuǎn)換。
3。使用C機(jī)器,可以是linux下的ftp命令,也可以是windows下的客戶端軟件,如果按照<1>做的話,那么就可以訪問B機(jī)器的21端口來連接后臺真正的ftp服務(wù)器(真正的端口是2121);
如果是按照<2>中的設(shè)置,則訪問的地址為本機(jī)IP。
............
N天之后又來接著寫下面的實(shí)戰(zhàn)體驗(yàn):
前面分析的好復(fù)雜,現(xiàn)在有點(diǎn)實(shí)戰(zhàn)經(jīng)驗(yàn)了,哈哈,下面就給出大家最最常用到的三種應(yīng)用場景,估計(jì)能滿足一大籃子人,先聲明一下:A->B代表A可以通過ssh連接B,注意這里只保證A能連接到B的一個(gè)端口(通常都是sshd的22端口),如果出現(xiàn)端口開放這種情況,那也不必打什么洞了,直接ssh連接好了,打洞不就為了能滲透進(jìn)去嘛,呵呵;假定userA和ipA分別是用戶名和機(jī)器ip地址。
A->B, 期望B->A, 解法: 在A上執(zhí)行ssh -R 12345:localhost:22 userB@ipB -Nfg; 使用時(shí)在B上執(zhí)行: ssh -p 12345 userA@localhost即可連接上A了;
B->A, B->C, 期望A->C(當(dāng)然C->A也同理), 解法: 在B上執(zhí)行ssh -R 12345:ipC:22 userA@ipA -Nfg; 使用時(shí)在A上執(zhí)行: ssh -p 12345 userC@localhost即可連接上C了;
A->B, B->C, 期望A->C, 解法: 在A上執(zhí)行ssh -L 12345:ipC:22 userB@ipB -Nfg; 使用時(shí)在A上執(zhí)行ssh -p 12345 userC@localhost即可連接上C了.
把這三種應(yīng)用玩熟了, 基本上就完全可以理解-R,-L,-D的奧妙了, 再玩出各種離奇的花樣也就不在話下了. 而且我這里都是把proxy架設(shè)在A上了,對于A自身來講,當(dāng)A使用自身的proxy時(shí)自然就用localhost就ok了,如果D能連接到A上的12345端口,那么D能就做A期待的事情了(比如去連接C之類的).
B->A, B->C, C->D, 期望A->D, 端口轉(zhuǎn)發(fā)的路徑為A:12345->C:54321->D:22, 實(shí)現(xiàn)第一步轉(zhuǎn)發(fā)需要在B上執(zhí)行ssh -R 12345:ipC:54321 userA@ipA -Nfg; 實(shí)現(xiàn)第二步轉(zhuǎn)發(fā)需要在C上執(zhí)行ssh -D 54321 userD@ipD -Nfg. 但這么做需要機(jī)器C能夠允許開放54321端口。
還有一種保守的解法如下:
B->A, B->C, C->D, 期望A->D, 我們可以先打通A->C, 問題就變成了A-C,
C->D, 期望A->D了, 然后再打通A->D即可, 實(shí)現(xiàn)A->C需要在B上執(zhí)行ssh -R
12345:ipC:22 userA@ipA -Nfg; 實(shí)現(xiàn)A->D需要在A上執(zhí)行ssh -p 12345 -L
54321:ipD:22 userC@localhost -Nfg; 接下來用ssh -p 54321 userD@localhost即可.
再告訴大家個(gè)好東西, 打通了之后, scp也能work了, 只是得用-P去指定端口而不是-p喲.
舉個(gè)例子來說,比如要在本機(jī)再開一個(gè)端口30000用于ssh,那么可以: ssh -Nfg -L 本機(jī)IP地址:30000:本機(jī)IP地址:22 localhost
對于ssh2,應(yīng)該這么寫:ssh -q -g -f -L 本機(jī)IP地址:30000:本機(jī)IP地址:22 localhost
對于端口轉(zhuǎn)發(fā),還可以用iptable實(shí)現(xiàn),參見:http://www.cyberciti.biz/faq/linux-port-redirection-with-iptables/
http://www.cyberciti.biz/faq/linux-port-redirection-with-iptables/
對于經(jīng)常ssh的那些host,可以搞一些簡單的alias分配給它們:
$ cat .ssh/config
Host pc1
Hostname 10.10.121.33
ssh -t admin@10.10.121.33 su test #在執(zhí)行su test命令之前搞出個(gè)虛擬的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這個(gè)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,登錄進(jìn)ServerA之后再連ServerB,登錄進(jìn)ServerB之后再連ServerC
如果不想敲很長的命令行,可以寫到config文件中:
vi ~/.ssh/config,并設(shè)定如下:
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