利用SSH Tunnel連線至內部網路

以往要連線回公司的內部網路,或是連線到某些限制只有公司IP可以使用的服務的時候通常是透過VPN來完成。但VPN有些麻煩的是它會利用VPN遠端的閘道取代原本的閘道,這樣一來原本閘道的路由就會斷線,其實有點麻煩,例如:我連到公司的VPN,但公司的網路會擋MSN Messenger的連線,所以連VPN的過程中MSN就會斷線了。(註:當然可以透過VPN會指定通過遠端閘道的路由規則)

所以如果在要連線的地方有一台開放SSH連線的Server的話,其實可以透過SSH Tunnel達到類似VPN的效果,透過SSH Tunnel可以連到遠端主機可以連到的任何主機,其實SSH Tunnel的運作簡單說就是透過SSH作為通道然後利用遠端主機作為跳板來連線。不過缺點是每個要連線的位置都需要設定,所以如果需要連10種服務就必須設定相對多次,數量一多設定起來其實也相當麻煩!

SSH Tunnel其實是實踐了一種所謂port forwarding的功能,所謂port forwarding就是將遠端的IP位址(address)與連接埠號(port number)利用另一組位址與埠號替代(在這邊就是用近端的位置取代)。我簡單的畫了一張SSH Tunnel連線的示意圖,一般而言Client端是無法連線到區網內沒有對外的主機的,例如區網內的主機(Dest. Host),可是如果透過區網內有開放SSH的主機(SSH Server)將遠端的IP位置與port號forward到近端,這樣Client端就可以存取到Dest. Host的服務。

SSH_Tunnel
(註:圖片是用gliffy(http://www.gliffy.com)畫的)

接下來的示範,設定都跟下圖一樣。藍色的部分是對外的IP,紅色則是區網內的IP。這邊假設SSH Server對外的IP是168.94.1.1 SSH的port是22、內部IP是192.168.1.101,我們要連線的Dest. Host的內部IP是192.168.2.102。

SSH_Tunnel_2

  1. Client端為Windows連法
  2. Client端為Unix/Linux的連法

Client端為Windows連法

因為Windows系統不是原生支援SSH所以需要用SSH Clinet端軟體來做SSH連線,而目前大部分的SSH Clinet端都支援直接設定SSH Tunnel,我慣用的Client端是PieTTY (http://ntu.csie.org/~piaip/pietty/),這邊也是用PieTTY來示範。PieTTY是PuTTY改良來的,優點是較支持中文,因此PuTTY的設定其實也差不多。

↓ 首先登入系統,PieTTY的登入介面就像下面這樣,只要把遠端的IP及Port選好,就可以連線。
SSH_Tunnel_3

↓ 然後選擇 選項 > 詳細設定
SSH_Tunnel_4

↓ 在詳細設定裡面的 Connection > SSH > Tunnels就可以找到SSH Tunnel的設定介面。只要填入Source port還有Destination就可以了。Source Port是指待會要連localhost所用的port,只要設定一組目前本機沒有被占用的port就可以了,這邊的例子用的是31280 port。而Destination要填入SSH Server要連的主機名稱或是IP及服務的port,主機名稱與port用冒號 ( : ) 分隔,現在假設我們要連80 port就打入 192.168.1.102:80,如果DEST. HOST有domain的話也可以換成主機名稱。設定完成後壓Add就會進入上面的清單,壓Apply的話才會生效。
SSH_Tunnel_5

設定完畢後,只要連localhost的31280就等於存取192.168.1.102:80。

Client端為Unix/Linux的連法

因為大多數Unix-like系統都直接支援SSH指令,因此只要在在命令列中下指令就可以開啟SSH Tunnel。指令也很簡單,一行搞定

ssh -N -f -L LOCAL_PORT:DEST_HOST:DEST_HOST_PORT SSH_USER@SSH_SERVER_IP

例如: ssh -N -f -L 31280:192.168.1.102:80 ssh_user@168.95.1.1

說明一下指令。

-N 連線後不執行指令
-f 連線後背景執行
-L 是啟用SSH Tunnel

↓ 連線後下查目前所有聆聽port的指令 ( netstat -ntulp ) 就會發現31280 port就被ssh這個程式佔用了。所以現在連線localhost的31280 port就等於存取遠端的192.168.1.102:80。如果要關閉的話則可以下kill指令把這個ssh process殺掉。
SSH_Tunnel_6