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