ssh 命令除了登陸外還有三種代理功能:

  • 正向代理(-L):相當於 iptable 的 port forwarding
  • 反向代理(-R):相當於 frp 或者 ngrok
  • socks5 代理(-D):相當於 ss/ssr

如要長期高效的服務,應使用對應的專用軟體。如沒法安裝軟體,比如當你處在限制環境下想要訪問下某個不可達到的目標,或者某個臨時需求,那麼 ssh 就是你的兜底方案。

正向代理:

所謂「正向代理」就是在本地啟動埠,把本地埠數據轉發到遠端。

用法1:遠程埠映射到其他機器

HostB 上啟動一個 PortB 埠,映射到 HostC:PortC 上,在 HostB 上運行:

HostB$ ssh -L 0.0.0.0:PortB:HostC:PortC user@HostC

這時訪問 HostB:PortB 相當於訪問 HostC:PortC(和 iptable 的 port-forwarding 類似)。

用法2:本地埠通過跳板映射到其他機器

HostA 上啟動一個 PortA 埠,通過 HostB 轉發到 HostC:PortC上,在 HostA 上運行:

HostA$ ssh -L 0.0.0.0:PortA:HostC:PortC user@HostB

這時訪問 HostA:PortA 相當於訪問 HostC:PortC。

兩種用法的區別是,第一種用法本地到跳板機 HostB 的數據是明文的,而第二種用法一般本地就是 HostA,訪問本地的 PortA,數據被 ssh 加密傳輸給 HostB 又轉發給 HostC:PortC。

反向代理:

所謂「反向代理」就是讓遠端啟動埠,把遠端埠數據轉發到本地。

HostA 將自己可以訪問的 HostB:PortB 暴露給外網伺服器 HostC:PortC,在 HostA 上運行:

HostA$ ssh -R HostC:PortC:HostB:PortB user@HostC

那麼鏈接 HostC:PortC 就相當於鏈接 HostB:PortB。使用時需修改 HostC 的 /etc/ssh/sshd_config,添加:

GatewayPorts yes

相當於內網穿透,比如 HostA 和 HostB 是同一個內網下的兩臺可以互相訪問的機器,HostC是外網跳板機,HostC不能訪問 HostA,但是 HostA 可以訪問 HostC。

那麼通過在內網 HostA 上運行 ssh -R 告訴 HostC,創建 PortC 埠監聽,把該埠所有數據轉發給我(HostA),我會再轉發給同一個內網下的 HostB:PortB。

同內網下的 HostA/HostB 也可以是同一臺機器,換句話說就是內網 HostA 把自己可以訪問的埠暴露給了外網 HostC。

按照前文《韋易笑:內網穿透:在公網訪問你家的 NAS》中,相當於再 HostA 上啟動了 frpc,而再 HostC 上啟動了 frps。

本地 socks5 代理

在 HostA 的本地 1080 埠啟動一個 socks5 服務,通過本地 socks5 代理的數據會通過 ssh 鏈接先發送給 HostB,再從 HostB 轉發送給遠程主機:

HostA$ ssh -D localhost:1080 HostB

那麼在 HostA 上面,瀏覽器配置 socks5 代理為 127.0.0.1:1080,看網頁時就能把數據通過 HostB 代理出去,類似 ss/ssr 版本,只不過用 ssh 來實現。

使用優化

為了更好用一點,ssh 後面還可以加上:-CqTnN 參數,比如:

$ ssh -CqTnN -L 0.0.0.0:PortA:HostC:PortC user@HostB

其中 -C 為壓縮數據,-q 安靜模式,-T 禁止遠程分配終端,-n 關閉標準輸入,-N 不執行遠程命令。此外視需要還可以增加 -f 參數,把 ssh 放到後臺運行。

這些 ssh 代理沒有短線重連功能,鏈接斷了命令就退出了,所以需要些腳本監控重啟,或者使用 autossh 之類的工具保持鏈接。

功能對比

正向代理(-L)的第一種用法可以用 iptable 的 port-forwarding 模擬,iptable 性能更好,但是需要 root 許可權,ssh -L 性能不好,但是正向代理花樣更多些。反向代理(-R)一般就作為沒有安裝 frp/ngrok/shootback 時候的一種代替,但是數據傳輸的性能和穩定性當然 frp 這些專用軟體更好。

socks5 代理(-D)其實是可以代替 ss/ssr 的,區別和上面類似。所以要長久使用,推薦安裝對應軟體,臨時用一下 ssh 挺順手。

--

補充下 iptable 的 port-forwarding 怎麼設置,十分管用的功能,兩個函數即可:

#! /bin/sh

# create forward rule by source interface
# http://serverfault.com/questions/532569/how-to-do-port-forwarding-redirecting-on-debian
PortForward1() {
local IN_IF=$1
local IN_PORT=$2
local OUT_IP=$3
local OUT_PORT=$4
local IPTBL="/sbin/iptables"
echo "1" > /proc/sys/net/ipv4/ip_forward
$IPTBL -A PREROUTING -t nat -i $IN_IF -p tcp --dport $IN_PORT -j DNAT --to-destination ${OUT_IP}:${OUT_PORT}
$IPTBL -A FORWARD -p tcp -d $OUT_IP --dport $OUT_PORT -j ACCEPT
$IPTBL -A POSTROUTING -t nat -j MASQUERADE
}

# create forward rule by source ip
# http://blog.csdn.net/zzhongcy/article/details/42738285
ForwardPort2() {
local IN_IP=$1
local IN_PORT=$2
local OUT_IP=$3
local OUT_PORT=$4
local IPTBL="/sbin/iptables"
echo "1" > /proc/sys/net/ipv4/ip_forward
$IPTBL -t nat -A PREROUTING --dst $IN_IP -p tcp --dport $IN_PORT -j DNAT --to-destination ${OUT_IP}:${OUT_PORT}
$IPTBL -t nat -A POSTROUTING --dst $OUT_IP -p tcp --dport $OUT_PORT -j SNAT --to-source $IN_IP
}

第一個函數是按照網卡名稱設置轉發:

PortForward1 eth1 8765 202.115.8.2 8765

這時,本地 eth1 網卡的 8765 埠就會被轉發給 202.115.8.2 的 8765 埠。

第二個函數是按照本機的 ip 地址,比如本機是 192.168.1.2:

PortForward2 192.168.1.2 8765 202.115.8.2 8765

那麼任何訪問本機 192.168.1.2 這個地址 8765 埠,都會被轉發到 202.115.8.2:8765

這個 iptable 的 port forwarding 是內核層運行的,性能極好,只不過每次重啟都需要重新設置下。

推薦閱讀:

相關文章