SSH端口转发命令的理解
以以下字符画情景为例, AB/BC两对电脑互相连接而AC电脑之间没有连接.
+--------------------+ +-------------------------------------------+
| | | |
| | | |
| +----------------+ | | |
| | | | | |
| +----------------+ | | |
| | ping IPA | |
| | +----------------> | |
| +----+ | | |
| | | | <----------------+ | |
| | | | ping IPB XX-------------------------------------------X
| | | | X X
| | | | XX XX
| | | | XX X
| | | | XX XX
| | | | XX XX
| | | | XX XX
| | | | XX XXX
| | | | +------------------------------------------+X
| | | |
| +----+ | 电脑A +
| | 电脑B IPA |
| | IPB XX | XX
+--------------------+ X | X
XXX 电脑A与C之间不连接, 无法互ping
^ + XX|X
ping IPB | | ping IPC XXX | X
| | XX | XX
+ v +
+--------------------------------------------------------------------+
| || 电脑C || |
| || IPC || |
| || +-------------------------------+ || |
| || +-------------------------------+ || |
| || || |
| || || |
+--------------------------------------------------------------------+
静态转发
- A为了让A能够连上C, 以B为跳板将C的端口转发至A, 在A中执行:
ssh -CN -L A的端口(portA):C的IP(IPC):C的端口(portC) B的用户名@B的IP(IPB) &
随后A访问自己的portA, 即可发现获取到了访问C的portC才能得到的数据. 换句话说, A在访问自己的portA时, 实际上将访问信息给了B, 请B代为访问C的portC端口并将结果返回给A的portA端口.
其中A的portA与B(的ssh端口)之间的数据传输被ssh加密, 但是B与C的portC之间的数据传输没有. 如果希望B与C的portC之间的数据传输也被加密, 则需要将命令改成:
# 在B中运行
ssh -CN -L B的临时端口(portB):C的本地IP(localhost):C的端口(portC) C的用户名@C的IP(IPC) &
# 在A中运行
ssh -CN -L A的端口(portA):B的本地IP(localhost):B的临时端口(portB) B的用户名@B的IP(IPB) &
如果有一台只与A连接的电脑D想与C连接, 可以使用参数
-g允许D连接A的端口portA, 即ssh -CNg -L …. 当然D与A的portA的连接没有加密, 如果需要加密, 那还得在D中运行ssh -CN -L D的端口(portD):A的本地IP(localhost):B的端口(portA) A的用户名@A的IP(IPA) &如果网速够快, 可以不用对数据进行压缩, 即不需要
-C参数, 将命令变为ssh -N -L ….
- B为了让A连上C, 以B为跳板将C的端口转发至A, 在B中执行:
ssh -CN -R A的端口(portA):C的IP(IPC):C的端口(portC) A的用户名@A的IP(IPA) &
可以发现不管是
-L还是-R类型的转发, 后面接的都是目标机端口:源机IP:源机端口 需认证机用户名@IP. 需认证机有两类, 一类是跳板机, 一类是目标机.
-L类转发是在目标机上执行的命令, 因此需要认证跳板机;-R类转发是在跳板机上执行的命令, 因此需要认证目标机.
动态转发
在上述静态转发中, 每次A访问localhost:portA(本机portA端口)时都只能到达C的端口portC. 内不能不指定目标IP与端口从而让A访问到B能够访问到的所有资源? 换句话说让B作为A的网络代理并且A/B之间的通讯为加密通讯. 命令见下:
ssh -CN -D A的端口(portA) B的用户名:B的IP(IPB) &
这样能够创建一个A/B之间的socks v5隧道. 在支持socks v5网络代理的软件(比如火狐浏览器)中就能够通过配置A的网络代理为socks://localhost:portA实现B所在的网络的访问.
应用举例
加密数据连接
命令
我的Rstudio server是通过http来连接服务器的, 传输过程是明文, 容易被人监听, 而申请SSL/TLS证书”又贵又繁琐”, 故考虑使用SSH转发目标端口到本地后使用.
ssh -N -L 本地端口:localhost:服务器上的目标端口 服务器用户名@服务器IP
随后在浏览器里面打开http://localhost:本地端口即可, Firefox也不会总是跳出来连接不安全的提示了.
顺便可以用这种方法加密一下VNC远程桌面的连接.
脚本
对于GNU/Linux我写了一个脚本来方便进行ssh端口转发. 建议将这个脚本放在/usr/local/bin/ssh-forward.
#! /bin/zsh
REMOTEPORT=`echo $1 | cut -d':' -f2`
if [ -z ${REMOTEPORT} ]; then
echo "Usage: ssh-forward username@remote-IP:remote-port local-port"
return 1
fi
LOCALPORT=$2
if [ -z ${LOCALPORT} ]; then
LOCALPORT=${REMOTEPORT}
echo "Warning: local-port is omitted and remote-port is used as local-port"
fi
ssh -N -L ${LOCALPORT}:localhost:${REMOTEPORT} `echo $1 | cut -d':' -f1`
内网穿透
我们连接的网络大多不是真正的公网, 而是经过NAT层层转发连接起来的内网. 所以我们能够访问公网上的网站, 公网上的主机却无法访问我们自己.
假设A处在公网中国, B在NAT后面的内网中, B能够访问A, A无法访问B. 通过-R类型的转发可以让A访问到B或者与B连接互ping的主机.
如果有一台公网的GNU/Linux或者BSD服务器, 可以用下述命令实现穿透.
ssh -CNg -R 公网服务器端口:内网机器IP(localhost):内网机器端口 公网服务器用户名:公网服务器IP &
通过socks代理连接网络
在动态转发中实现了A访问B所处的网络. 如果B能上公网而A不能上公网, 则可通过该种方法让A连入Internet, 实现网上冲浪. 注意必须在软件中指明使用socks v5时代理DNS查询, 否则使用域名的网站都无法打开.
如果A在中国, B在美国, 那么不就实现了”科学上网”了.
反过来, 如果A在公网, B为内网与公网的连接点, 这可以使用这种方式实现类似反向VPN的效果.
Shell socks代理设置
在shell中运行的命令比如git/apt等并不会主动走socks代理(电脑B), 为了迫使它们使用代理上网, 可以使用proxychains. 下载最新的源码包, 解压, 进入其目录, 使用./configure && make && sudo make install && sudo cp ./src/proxychains.conf /etc/完成安装. 将/etc/proxychains.conf中的socks4 127.0.0.1 9050修改为socks5 127.0.0.1 portA即完成配置. 使用时在命令前加上proxychains4即可迫使命令利用代理上网.
为了方便使用可以将/usr/local/bin/proxychains4软链接为/usr/local/bin/p, 在命令前直接加上p即可使用代理.
整理一下proxychain的安装配置代码见下:
portA=**** # 设置portA
wget https://github.com/rofl0r/proxychains-ng/archive/refs/tags/v4.14.zip
unzip v4.14.zip
cd proxychains-ng-4.14
./configure
make
sudo make install
sudo sed "s/socks4 127\.0\.0\.1 9050/socks5 127\.0\.0\.1 ${portA}" ./src/proxychains.conf > /etc/proxychains.conf
cd ..
rm -r proxychains-ng-4.14
rm v4.14.zip
cd /usr/local/bin
sudo ln -s proxychains4 p
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!