https://segmentfault.com/a/1190000021888536
https://zhuanlan.zhihu.com/p/57630633
SSH 命令的三種代理功能(-L/-R/-D)
ssh 命令除了登陸外還有三種代理功能:
如要長期高效的服務,應使用對應的專用軟件。如沒法安裝軟件,比如當你處在限制環境下想要訪問下某個不可達到的目標,或者某個臨時需求,那么 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
是內核層運行的,性能極好,只不過每次重啟都需要重新設置下。
ssh參數說明
格式;
ssh [user@]host [command] 選項:
- -1:強制使用ssh協議版本1
- -2:強制使用ssh協議版本2
- -4:強制使用IPv4地址
- -6:強制使用IPv6地址
- -A:開啟認證代理連接轉發功能
- -a:關閉認證代理連接轉發功能
- -b:使用本機指定地址作為對應連接的源ip地址
- -C:請求壓縮所有數據
- -c:選擇所加密的密碼型式 (blowfish|3des 預設是3des)
- -e:設定跳脫字符
- -F:指定ssh指令的配置文件
- -f:后台執行ssh指令
- -g:允許遠程主機連接主機的轉發端口
- -i:指定身份文件(預設是在使用者的家目錄 中的 .ssh/identity)
- -l:指定連接遠程服務器登錄用戶名
- -N:不執行遠程指令
- -n:重定向stdin 到 /dev/null
- -o:指定配置選項
- -p:指定遠程服務器上的端口(默認22)
- -P:使用非特定的 port 去對外聯機(注意這個選項會關掉 RhostsAuthentication 和 RhostsRSAAuthentication)
- -q:靜默模式
- -T:禁止分配偽終端
- -t:強制配置 pseudo-tty
- -v:打印更詳細信息
- -X:開啟X11轉發功能
- -x:關閉X11轉發功能
- -y:開啟信任X11轉發功能
- -L listen-port:host:port 指派本地的 port 到達端機器地址上的 port
- 建立本地SSH隧道(本地客戶端建立監聽端口)
- 將本地機(客戶機)的某個端口轉發到遠端指定機器的指定端口.
- -R listen-port:host:port 指派遠程上的 port 到本地地址上的 port
- 建立遠程SSH隧道(隧道服務端建立監聽端口)
- 將遠程主機(服務器)的某個端口轉發到本地端指定機器的指定端口.
- -D port 指定一個本地機器 “動態的’’ 應用程序端口轉發.
ssh 通過代理機跳轉內網
ssh 命令有一種簡單的方法來利用跳板主機通過單個命令連接到遠程主機。 ssh 可以使用 ProxyJump 創建初始和第二個連接,而不是首先通過 SSH 連接到跳板主機,然后在跳板上使用 ssh 連接到遠程主機。
ProxyJump 或 -J 標志是在 ssh 7.3 版中引入的。要使用它,請在 -J 標志后指定要連接的跳板機,以及遠程主機:
語法規則如下
- 通過 jump-host 登陸 remote-host
$ ssh -J <jump-host> <remote-host>
- 如果主機端口不同, 可使用如下命令
$ ssh -J user@<jump-host:port> <user@remote:port>
- scp 使用跳板機上傳文件的命令
$ scp -o 'ProxyJump jump.host' myfile.txt remote.host:/my/dir
如果需要多個跳轉, 多個跳板機使用逗號隔開
ssh -J <jump.host1>,<jump.host2> <remote>
另外另種方式是:
- ssh tunnel
- ProxyCommand