SSH端口轉發及內網穿透

大家都知道SSH是一種安全的傳輸協議,用在連接服務器上比較多。不過其實除了這個功能,它的隧道轉發功能更是吸引人。下面是個人根據自己的需求以及在網上查找的資料配合自己的實際操作所得到的一些心得。

SSH/plink命令的基本資料:

首先,認識下這三個非常強大的命令:

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連用,不用登錄到遠程主機。

-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參數中,允許遠程主機連接到建立的轉發的端口,如果不加這個參數,只允許本地主機建立連接。注:這個參數我在實踐中似乎始終不起作用。

以上摘錄自:http://chenweiguang.blogspot.com/2009/03/ssh.html

建立本地SSH隧道例子

在我們計劃建立一個本地SSH隧道之前,我們必須清楚下面這些數據:

  1. 中間服務器d的IP地址

  2. 要訪問服務器c的IP地址

  3. 要訪問服務器c的端口

現在,我們把上面這張圖變得具體一些,給這些機器加上IP地址。並且根據下面這張圖列出我們的計劃:

Chapter 8 Secure Network (ssh端口映射) - linux-ul - unix-EA

 

  1. 需要訪問234.234.234.234的FTP服務,也就是端口21

  2. 中間服務器是123.123.123.123

現在我們使用下面這條命令來達成我們的目的(192.168.0.100上執行)

1.ssh -N -f   -L    2121:234.234.234.234:21    123.123.123.123

2.ftp://localhost:2121        # 現在訪問本地2121端口,就能連接234.234.234.234的21端口了

這裏我們用到了SSH客戶端的三個參數,下面我們一一做出解釋:

  • -N 告訴SSH客戶端,這個連接不需要執行任何命令。僅僅做端口轉發

  • -f 告訴SSH客戶端在後臺運行

  • -L 做本地映射端口,被冒號分割的三個部分含義分別是

    • 需要使用的本地端口號

    • 需要訪問的目標機器IP地址(IP: 234.234.234.234)

    • 需要訪問的目標機器端口(端口: 21)

  • 最後一個參數是我們用來建立隧道的中間機器的IP地址(IP: 123.123.123.123)

 

我們再重複一下-L參數的行爲。-L X:Y:Z的含義是,將IP爲Y的機器的Z端口通過中間服務器映射到本地機器的X端口。

在這條命令成功執行之後,我們已經具有繞過公司防火牆的能力,並且成功訪問到了我們喜歡的一個FTP服務器了。

如何建立遠程SSH隧道

通過建立本地SSH隧道,我們成功地繞過防火牆開始下載FTP上的資源了。那麼當我們在家裏的時候想要察看下載進度怎麼辦呢?大多數公司的網絡是通過路由器接入互聯網的,公司內部的機器不會直接與互聯網連接,也就是不能通過互聯網直接訪問。通過線路D-B-A訪問公司裏的機器a便是不可能的。也許你已經注意到了,雖然D-B-A這個方向的連接不通,但是A-B-D這個方向的連接是沒有問題的。那麼,我們能否利用一條已經連接好的A-B-D方向的連接來完成D-B-A方向的訪問呢?答案是肯定的,這就是遠程SSH隧道的用途。

與本地SSH一樣,我們在建立遠程SSH隧道之前要清楚下面幾個參數:

  • 需要訪問內部機器的遠程機器的IP地址(這裏是123.123.123.123)

  • 需要讓遠程機器能訪問的內部機器的IP地址(這裏因爲是想把本機映射出去,因此IP是127.0.0.1)

  • 需要讓遠程機器能訪問的內部機器的端口號(端口:22)

在清楚了上面的參數後,我們使用下面的命令來建立一個遠程SSH隧道

1.ssh -N -f -R 2222:127.0.0.1:22      123.123.123.123

現在,在IP是123.123.123.123的機器上我們用下面的命令就可以登陸公司的IP是192.168.0.100的機器了。

1.ssh -p 2222 localhost

-N,-f 這兩個參數我們已經在本地SSH隧道中介紹過了。我們現在重點說說參數-R。該參數的三個部分的含義分別是:

  • 遠程機器使用的端口(2222)

  • 需要映射的內部機器的IP地址(127.0.0.1)

  • 需要映射的內部機器的端口(22)

例如:-R X:Y:Z 就是把我們內部的Y機器的Z端口映射到遠程機器的X端口上。







SSH端口轉發的好處:

    1. 利用SSH通道天然的加密特性

    2. 通過具備訪問權限的第三者,突破防火牆對自己的限制,或者隱身


角色定義:

    A. 本地服務器,想通過中間服務器B間接訪問目標服務器C

    B. 中間服務器,類似於代理,A以B的名義去訪問C

    C. 目標服務器,C看到的都是中間服務器B在訪問自己


1. 本地端口轉發

命令:

    ssh -Nf -L [local_A_address]:local_A_port:target_C_server:target_C_port via_B_server

參數:

    -N,不執行命令

    -f,後臺執行

    -L,local本地端口轉發

    local_A_address:

        127.0.0.1 - 默認,只能本機使用這個端口轉發

        也可以是本機的IP地址,同時其他人可以使用這個IP來使用這個端口轉發

    via_B_server:中間服務器

應用:

    A---能訪問------>B-------能訪問------>C

    A---不能訪問----------------------------->C

    A---通過本機端口,以B的名義訪問-->C

關閉:

    直接kill -9 建立的SSH連接,下同


2. 遠程端口轉發

命令:

    ssh -Nf -R [local_A_address]:local_A_port:target_C_server:target_C_port local_A_address

參數:

    -R,remote,遠程端口轉發

    local_A_address,這個地址爲A的IP

應用:

    環境和目的 與 本地端口轉發是一樣的,這裏只是不在本地服務器A上執行命令,而是在中間服務器B上執行

    爲什麼不直接在服務器A自己身上執行命令呢?這個場景有別於本地端口轉發的地方在於A不能主動連接B但反之可以,比如A在外網,B在內網

    而A去訪問的時候,同樣都是通過自己的IP和端口,同樣首先建立AB之間的SSH通道,以服務器B的名義來訪問目標服務器C。


3. 動態端口轉發

命令:

    ssh -Nf -D [local_A_address]:local_A_port via_B_server

參數:

    -D,dynamic,動態端口轉發

應用:

    本地和遠程端口轉發,都限定了目標服務器以及目標服務器的端口;

    而動態端口轉發,A把B作爲了自己的全權代理,不限定目標服務器及其端口;

    這裏要求在A上,做下代理設置,比如瀏覽器的代理設定爲自己的IP:PORT;

    本地端口轉發和遠程端口轉發,其實都可看着是動態端口轉發(代理)的子集

    三者和一般代理的目的和場景都一致,區別在於這裏自己A和代理服務器B之前的所有連接都是基於加密的SSH。





三、建立SSH隧道的幾個技巧


自動重連

  隧道可能因爲某些原因斷開,例如:機器重啓,長時間沒有數據通信而被路由器切斷等等。因此我們可以用程序控制隧道的重新連接,例如一個簡單的循環或者使用 djb’s daemontools . 不管用哪種方法,重連時都應避免因輸入密碼而卡死程序。關於如何安全的避免輸入密碼的方法,請參考我的如何實現安全的免密碼ssh登錄 。這裏請注意,如果通過其他程序控制隧道連接,應當避免將SSH客戶端放到後臺執行,也就是去掉-f參數。

保持長時間連接

  有些路由器會把長時間沒有通信的連接斷開。SSH客戶端的TCPKeepAlive選項可以避免這個問題的發生,默認情況下它是被開啓的。如果它被關閉了,可以在ssh的命令上加上-o TCPKeepAlive=yes來開啓。

另一種方法是,去掉-N參數,加入一個定期能產生輸出的命令。例如: top或者vmstat。下面給出一個這種方法的例子:

ssh -R 2222:localhost:22 123.123.123.123 "vmstat 30"

 

檢查隧道狀態

  有些時候隧道會因爲一些原因通信不暢而卡死,例如:由於傳輸數據量太大,被路由器帶入stalled狀態。這種時候,往往SSH客戶端並不退出,而是卡死在 那裏。一種應對方法是,使用SSH客戶端的ServerAliveInterval和ServerAliveCountMax選項。 ServerAliveInterval會在隧道無通信後的一段設置好的時間後發送一個請求給服務器要求服務器響應。如果服務器在 ServerAliveCountMax次請求後都沒能響應,那麼SSH客戶端就自動斷開連接並退出,將控制權交給你的監控程序。這兩個選項的設置方法分 別是在ssh時加入-o ServerAliveInterval=n和-o ServerAliveCountMax=m。其中n, m可以自行定義。

如何將端口綁定到外部地址上

  使用上面的方法,映射的端口只能綁定在127.0.0.1這個接口上。也就是說,只能被本機自己訪問到。如何才能讓其他機器訪問這個端口呢?我們可以把這個 映射的端口綁定在0.0.0.0的接口上,方法是加上參數-b 0.0.0.0。同時還需要打開SSH服務器端的一個選項-GatewayPorts。默認情況下它應當是被打開的。如果被關閉的話,可以在/etc /sshd_config中修改GatewayPorts no爲GatewayPorts yes來打開它。

如何尋找中間服務器

如果你家裏使用ADSL上網,多半你會比較幸運。一般的ADSL(例如 聯通 的ADSL)都是有互聯網地址的。你只需要在家裏的路由器上一臺裝有OpenSSH server機器的SSH端口映射出去即可。同時一些提供SSH訪問的虛擬主機也可以用於這一用途。例如: Hostmonser 或者 Dreamhost .

 

四、通過SSH隧道建立SOCKS服務器

如果我們需要藉助一臺中間服務器訪問很多資源,一個個映射顯然不是高明的辦法(事實上,高明確實沒有用這個方法)。幸好,SSH客戶端爲我們提供了通過SSH隧道建立SOCKS服務器的功能。

通過下面的命令我們可以建立一個通過123.123.123.123的SOCKS服務器。

ssh -N -f -D 1080 123.123.123 # 將端口綁定在127.0.0.1上ssh -N -f -D 0.0.0.0:1080 123.123.123.123 # 將端口綁定在0.0.0.0上

 

通過SSH建立的SOCKS服務器使用的是SOCKS5協議,在爲應用程序設置SOCKS代理的時候要特別注意。

 

五、總結

至 此,我們已經對如何利用SSH隧道有一個基本的認識了。現在,文章開始時的那些問題應該迎刃而解了吧。這裏要特別說一下,由於SSH隧道也使用了SSH加 密協議,因此是不會被防火牆上的內容過濾器監控到的。也就是說一切在隧道中傳輸的數據都是被加密的。當然,離開隧道後的數據還是會保持自己原有的樣子,沒 有加密的數據還是會被後續的路由設備監控到。

 

 

PS:編者另注

  在大多數情況下,我們建立ssh隧道的時候,往往是想通過一臺公網的主機或者是大家都可以訪問的主機做跳轉機,來訪問內部或者外部不能直接訪問的機器。所以一般像這種情況下,請將跳轉機中的ssh服務器中的GatewayPorts設爲yes

  1.建立本地的ssh隧道時,可以指定本地主機的地址,如下:

ssh -Nf -L 192.168.0.100:2121:234.234.234.234:21 123.123.123.123

   那麼本地局域網的任何機器訪問192.168.0.100:2121都會自動被映射到234.234.234.234:21

  

  2.建立遠程的ssh隧道時,可以指定公網的主機地址,不過一般情況是要訪問內網的主機,所以這條命令應該在任何一臺內網主機上執行,比如在192.168.0.102的主機上運行:

ssh -Nf -R 123.123.123.123:2222:192.168.0.100:22 123.123.123.123

 只要在局域網裏192.168.0.102可以直接連接內網主機192.168.0.100,且192.168.0.102可以直接與公網主機123.123.123.123建立ssh連接。那麼任何外網主機通過訪問公網主機123.123.123.123:2222就會被連接到192.168.0.100:22,從而可以完成外網穿越NAT到內網的訪問,而不需要在內網網關和路由器上做任何操作。

   

  另外,你也可以通過Xshell、Putty等工具來實現Linux主機與本地windows的端口轉發、socket代理,還有一些像ProxyChains 工具的使用。

     轉載自:https://blog.csdn.net/dufufd/article/details/75578277


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章