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