ssh是個多用途的工具,不僅可以遠程登錄,還可以搭建socks代理、進行內網穿透,這是利用它的端口轉發功能來實現的。
所謂ssh端口轉發,就是在ssh連接的基礎上,指定 ssh client 或 ssh server 的某個端口作為源地址,所有發至該端口的數據包都會透過ssh連接被轉發出去;至於轉發的目標地址,既可以指定,也可以不指定,如果指定了目標地址,稱為定向轉發,如果不指定目標地址則稱為動態轉發:
- 定向轉發
定向轉發把數據包轉發到指定的目標地址。目標地址不限定是ssh client 或 ssh server,既可以是二者之一,也可以是二者以外的其他機器 - 動態轉發
動態轉發不指定目標地址,數據包轉發的目的地是動態決定的
因為ssh端口轉發是基於ssh連接的,所以如果ssh連接斷開,那么設置好的端口轉發也會隨之停止。
在設置端口轉發之前,必須確認ssh的端口轉發功能是打開的。
怎樣打開ssh的端口轉發功能?
ssh端口轉發功能默認是打開的。控制它的開關叫做 AllowTcpForwarding,位於ssh server的配置文件 /etc/ssh/sshd_config 里:
AllowTcpForwarding yes
如果修改的話需要重啟sshd服務才會生效。
怎樣設置端口轉發?
設置端口轉發之前要注意 iptables 設置,確保相應的端口未被屏蔽,如果嫌麻煩的話也可以臨時禁用 iptables:
# service iptables stop
定向轉發和動態轉發的設置方法是不一樣的,以下分別介紹。
設置定向轉發
定向轉發可以把一個 IP:Port 定向映射到另一個 IP:Port,源和目的都必須指定。源地址既可以是 ssh client 的某個端口,也可以是 ssh server 的某個端口:
- 如果源地址是 ssh client 的某個端口,稱為本地轉發(Local Port Forwarding),發往 ssh client 指定端口的數據包會經過 ssh server 進行轉發;
- 如果源地址是 ssh server 的某個端口,則稱為遠程轉發(Remote Port Forwarding),發往 ssh server 指定端口的數據包會經過 ssh client 進行轉發.
設置本地轉發:
先看一下基本命令:
在ssh client上執行:
{ssh client}# ssh -g -N -f -o ServerAliveInterval=60 \
-L <local port>:<remote host>:<remote port> username@<ssh server>
參數的含義在后面有解釋。
我們以下面的示意圖為例:你想telnet連接{remote host},但是無法直達,你只能直接連接ssh client,於是試圖通過{ssh client}到{ssh server}這條通道中轉:
{you} — {ssh client} — {ssh server} — {remote host}
我們要做的是在{ssh client}上執行以下命令:
{ssh client} # ssh -g -L 2323:<remote-host>:23 username@<ssh-server>
輸入口令之后,就跟普通的ssh登錄一樣,我們進入了shell,在shell中可以正常操作,不同之處是,它同時還把 {ssh client} 的2323端口映射到了{remote host} 的23端口——亦即telnet端口,此后執行”telnet <ssh client> 2323″就相當於”telnet <remote-host>”,只要shell不退出,這個定向轉發就一直有效。
- 注1:如果以上命令不加”-g”選項,那么SSH Client上的監聽端口2323會綁定在127.0.0.1上,意味着只有SSH Client自己才能連上。加上”-g”選項之后,SSH Client才允許網絡上其他機器連接2323端口。
- 注2:以上命令會生成一個shell,有時候並不符合我們的需要,因為多數時候我們只想要一個端口轉發功能,掛一個shell是個累贅,而且shell一退出,端口轉發也停了。這就是為什么我們需要”-N -f”選項的原因:
-N 告訴ssh client,這個連接不需要執行任何命令,僅做端口轉發
-f 告訴ssh client在后台運行 - 注3:為了避免長時間空閑導致ssh連接被斷開,我們可以加上”-o ServerAliveInterval=60″選項,每60秒向ssh server發送心跳信號。還有一個TCPKeepAlive選項的作用是類似的,但是不如ServerAliveInterval 好,因為TCPKeepAlive在TCP層工作,發送空的TCP ACK packet,有可能會被防火牆丟棄;而ServerAliveInterval 在SSH層工作,發送真正的數據包,更可靠些。
- 如果不是以root身份設置端口轉發的話,轉發端口只能使用大於1024的端口號。
設置遠程轉發:
先看一下基本命令,分為兩部分:
在ssh server上:
編輯 /etc/ssh/sshd_config,設置以下內容然后重啟sshd服務
GatewayPorts yes
在ssh client上執行:
{ssh client}# ssh -f -N -o ServerAliveInterval=60 \
-R <ssh server port>:<remote host>:<remote port> username@<ssh server>
這次的實例如下所示,你想用telnet連接{remote host},但是無法直達,於是試圖通過{ssh server}到{ssh client}這條通道中轉,注意與前面介紹的本地轉發的不同之處是,本地轉發的案例中你只能直接連接到 ssh client,而這里你只能直接連到 ssh server:
{you} — {ssh server} — {ssh client} — {remote host}
我們要做的是在{ssh client}上執行以下命令:
{ssh client} # ssh -f -N -R 2323:<remote-host>:23 username@<ssh-server>
輸入口令之后,{ssh server}的2323端口映射到了{remote host}的23端口——亦即telnet端口,此后執行”telnet <ssh server> 2323″就相當於”telnet <remote-host>”。
本地轉發與遠程轉發的區別與適用場景
定向轉發(包括本地轉發和遠程轉發)通常用於內網穿透,本地轉發和遠程轉發的區別就在於監聽端口是開在ssh client上還是ssh server上。常見的使用場景是:
- 如果ssh client在內網里面,ssh server在Internet上,你想讓Internet上的機器穿進內網之中,那就使用遠程轉發;
- 如果ssh server在內網里面,ssh client在外面,你想穿進內網就應該使用本地轉發。
設置動態轉發
定向轉發(包括本地轉發和遠程轉發)的局限性是必須指定某個目標地址,如果我們需要借助一台中間服務器訪問很多目標地址,一個一個地定向轉發顯然不是好辦法,這時我們要用的是ssh動態端口轉發,它相當於建立一個SOCKS服務器。
先看一下基本命令:
在ssh client上執行:
{ssh client}# ssh -f -N -o ServerAliveInterval=60 \
-D <ssh client port> username@<ssh server>
實際使用時有兩種常見場景:
- 你把自己的機器(127.0.0.1)當作 sock5 代理服務器:
{you / ssh client} — {ssh server} — {other hosts}
命令如下:
{ssh client} # ssh -f -N -D 1080 username@<ssh-server>
這種情況下,我們得到的socks5代理服務器是:127.0.0.1:1080,僅供ssh client自己使用。
然后你就可以在瀏覽器中或其他支持socks5代理的軟件中進行設置。
- ssh client 和 ssh server 是同一台機器,並充當socks5代理:
{you} — {ssh client / ssh server} — {other hosts}
命令如下:
{ssh client} # ssh -f -N -g -D 1080 username@127.0.0.1
這種情況下,我們得到的socks5代理服務器是:
{ssh client IP}:1080,可供網絡上其他機器使用,只要能連接ssh client即可。
通過SSH建立的SOCKS服務器使用的是SOCKS5協議,在為應用程序設置SOCKS代理的時候要注意。