Dropbear SSH 完全指南 / 06 - 端口转发
第六章:端口转发
6.1 SSH 端口转发概述
SSH 端口转发(Port Forwarding)是 SSH 最强大的功能之一,它通过 SSH 加密通道转发任意 TCP 流量,本质上将 SSH 连接变为一条加密隧道。
端口转发类型
| 类型 | 命令选项 | 方向 | 说明 |
|---|---|---|---|
| 本地转发 (Local) | -L | 本地 → 远程 | 将本地端口映射到远程服务 |
| 远程转发 (Remote) | -R | 远程 → 本地 | 将远程端口映射到本地服务 |
| 动态转发 (Dynamic/SOCKS) | -D | 双向 | 创建 SOCKS 代理 |
| X11 转发 | -X | 远程 → 本地 | 转发图形界面 |
数据流对比图
本地转发 (-L):
[本地应用] → [本地端口] ═══SSH═══▶ [远程主机:端口]
远程转发 (-R):
[远程应用] → [远程端口] ═══SSH═══▶ [本地主机:端口]
动态 SOCKS (-D):
[本地应用] → [SOCKS代理] ═══SSH═══▶ [任意远程主机:端口]
6.2 本地端口转发(Local Forwarding)
本地端口转发是最常用的转发方式,它将本地的某个端口映射到通过 SSH 可达的远程服务。
基本语法
dbclient -L [bind_address:]local_port:destination_host:destination_port user@ssh_server
场景一:访问内网数据库
通过跳板机访问内网数据库服务器:
# 将本地 3307 端口映射到内网数据库服务器的 3306 端口
dbclient -L 3307:db-server.internal:3306 admin@jumphost
# 现在可以通过本地 3307 端口访问内网数据库
mysql -h 127.0.0.1 -P 3307 -u root -p
[你的电脑:3307] ═══SSH═══▶ [跳板机] → [db-server:3306]
场景二:访问内网 Web 服务
# 将本地 8080 映射到内网 Web 服务
dbclient -L 8080:intranet.company.com:80 admin@jumphost
# 浏览器访问 http://localhost:8080
场景三:安全访问嵌入式设备 Web UI
# 路由器管理界面通常使用 HTTP
# 通过 SSH 隧道加密访问
dbclient -L 8080:192.168.1.1:80 root@router-ssh
# 访问 https://localhost:8080
高级本地转发
# 绑定到所有接口(允许其他设备通过你的机器访问)
dbclient -L 0.0.0.0:8080:internal-web:80 admin@jumphost
# ⚠️ 安全风险:网络中的其他设备也可访问
# 绑定到特定接口
dbclient -L 127.0.0.1:8080:internal-web:80 admin@jumphost
# 多个转发规则
dbclient -L 3307:db:3306 -L 8080:web:80 -L 6380:redis:6379 admin@jumphost
# 后台运行
dbclient -f -N -L 8080:internal-web:80 admin@jumphost
# -f: 后台运行
# -N: 不执行远程命令
本地转发权限控制
Dropbear 服务端可以通过编译选项控制是否允许端口转发:
/* localoptions.h */
#define DROPBEAR_SVR_LOCALTCPFWD 1 /* 允许服务端本地转发 */
#define DROPBEAR_CLI_LOCALTCPFWD 1 /* 允许客户端本地转发 */
/* 设为 0 则禁用 */
# 服务端禁止本地端口转发
dropbear -j
6.3 远程端口转发(Remote Forwarding)
远程端口转发将远程服务器的端口映射到本地服务,常用于从外部访问内网设备。
基本语法
dbclient -R [bind_address:]remote_port:destination_host:destination_port user@ssh_server
场景一:暴露内网服务到公网
将内网的 Web 服务通过公网服务器暴露:
# 在内网设备上执行
dbclient -R 8080:localhost:80 admin@public-server
# 现在访问 public-server:8080 即可访问内网 Web 服务
[内网设备:80] ═══SSH═══▶ [公网服务器:8080] ← [外部用户]
场景二:IoT 设备远程调试
# 在 IoT 设备上建立反向隧道
dbclient -R 2222:localhost:22 admin@cloud-server
# 从云端连接到 IoT 设备
ssh -p 2222 root@localhost # 在 cloud-server 上执行
场景三:内网穿透方案
#!/bin/sh
# /etc/init.d/reverse-tunnel.sh - IoT 设备反向隧道脚本
CLOUD_SERVER="cloud.example.com"
CLOUD_USER="tunnel"
REMOTE_PORT="2222"
KEEPALIVE=30
start_tunnel() {
while true; do
dbclient -y -R "$REMOTE_PORT:localhost:22" \
-K "$KEEPALIVE" \
-o "ExitOnForwardFailure yes" \
"$CLOUD_USER@$CLOUD_SERVER"
echo "隧道断开,30 秒后重连..."
sleep 30
done
}
case "$1" in
start)
start_tunnel &
echo $! > /var/run/reverse-tunnel.pid
;;
stop)
kill $(cat /var/run/reverse-tunnel.pid 2>/dev/null) 2>/dev/null
;;
esac
远程转发的 GatewayPorts 配置
# 默认情况下,远程转发只绑定到 localhost
# 需要服务端配置 GatewayPorts
# Dropbear 使用 -a 选项允许任意主机连接到转发端口
dropbear -a # 允许远程转发绑定到所有接口
# 客户端指定绑定地址
dbclient -R 0.0.0.0:8080:localhost:80 admin@server
# 注意:服务端也需要 -a 选项才能生效
6.4 动态 SOCKS 代理
动态转发将 SSH 连接变为 SOCKS 代理,可以代理任意 TCP 流量。
基本用法
# 创建 SOCKS5 代理,监听本地 1080 端口
dbclient -D 1080 admin@remote-server
# 后台运行
dbclient -f -N -D 1080 admin@remote-server
# 绑定到所有接口
dbclient -D 0.0.0.0:1080 admin@remote-server
配置应用使用 SOCKS 代理
# curl 使用 SOCKS 代理
curl --socks5 127.0.0.1:1080 https://example.com
# wget
wget -e "https_proxy=socks5://127.0.0.1:1080" https://example.com
# Git
git config --global http.proxy socks5://127.0.0.1:1080
# 环境变量
export ALL_PROXY=socks5://127.0.0.1:1080
export http_proxy=socks5://127.0.0.1:1080
export https_proxy=socks5://127.0.0.1:1080
浏览器 SOCKS 代理配置
Firefox:
设置 → 常规 → 网络设置 → 手动代理配置
SOCKS 主机: 127.0.0.1
SOCKS 端口: 1080
☑ SOCKS v5
Chrome:
启动参数: --proxy-server="socks5://127.0.0.1:1080"
嵌入式设备 SOCKS 代理
在嵌入式设备上建立 SOCKS 代理,用于安全访问受限网络:
# 通过嵌入式设备的 SOCKS 代理访问内网
dbclient -D 1080 admin@embedded-device
# 通过该代理访问内网服务
curl --socks5 127.0.0.1:1080 http://192.168.1.100/api/status
6.5 X11 转发
X11 转发允许在本地显示远程的图形界面应用。
前提条件
# 服务端需要编译时启用 X11 转发
# localoptions.h:
#define DROPBEAR_X11FWD 1
# 服务端需要 xauth 工具
which xauth
# 客户端需要 X 服务器(Linux/macOS 默认有)
echo $DISPLAY
基本用法
# 启用 X11 转发
dbclient -X user@remote-server
# 在远程执行图形程序
xeyes
firefox &
gedit /path/to/file.txt
安全的 X11 转发
# 使用 -X(受信任的转发)
dbclient -X user@remote
# 安全限制
# -X 受信任模式:远程应用可以完全访问本地 X 服务器
# -x 受限制模式:Dropbear 不支持(OpenSSH 支持)
安全警告: X11 转发允许远程应用捕获本地屏幕内容和键盘输入。仅在信任远程服务器时使用。
6.6 Agent 转发
Agent 转发已在第五章详细介绍,此处仅简要回顾其在端口转发中的角色。
# Agent 转发用于跳板机场景
dbclient -A admin@jumphost
# 在跳板机上,可以通过转发的 Agent 认证到目标服务器
dbclient admin@target-server
# 无需在跳板机上存储私钥
安全替代方案
# 使用 ProxyJump 替代 Agent 转发
dbclient -J admin@jumphost admin@target
# 使用 ProxyCommand
dbclient -o "ProxyCommand dbclient -W %h:%p admin@jumphost" admin@target
6.7 转发隧道管理
后台隧道
# 启动后台隧道
dbclient -f -N -L 8080:internal:80 admin@jumphost
# 查看隧道进程
ps aux | grep dbclient
# 终止隧道
kill $(pgrep -f "dbclient.*8080")
隧道保活
# 启用 keepalive 防止隧道超时断开
dbclient -K 30 -N -L 8080:internal:80 admin@jumphost
# 完整的可靠隧道脚本
#!/bin/sh
TUNNEL_CMD="dbclient -N -L 8080:internal:80 -K 30 admin@jumphost"
while true; do
$TUNNEL_CMD
echo "隧道断开,5 秒后重连..."
sleep 5
done
多层隧道
[你的电脑] ══ SSH ══▶ [跳板机A] ══ SSH ══▶ [跳板机B] ══ SSH ══▶ [目标]
# 方法一:嵌套 ProxyCommand
dbclient \
-o "ProxyCommand dbclient -W %h:%p admin@jumphost-A" \
-o "ProxyCommand dbclient -W %h:%p admin@jumphost-B" \
admin@target
# 方法二:链式 -J
dbclient -J admin@jumphost-A,admin@jumphost-B admin@target
# 方法三:嵌套隧道
# 终端 1:建立到跳板机 A 的隧道
dbclient -L 2222:jumphost-B:22 admin@jumphost-A
# 终端 2:通过隧道 A 连接到跳板机 B
dbclient -p 2222 admin@localhost
# 终端 3:通过跳板机 B 建立到目标的隧道
dbclient -L 3333:target:22 admin@jumphost-B
# 终端 4:连接到目标
dbclient -p 3333 admin@localhost
6.8 转发调试
常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
Warning: remote port forwarding failed | 远程端口被占用 | 更换端口或检查服务端配置 |
channel_setup_fwd_listener: bind: Address already in use | 本地端口被占用 | 更换本地端口 |
Connection refused | 目标服务未运行 | 检查目标服务状态 |
Connection timed out | 网络不通 | 检查网络连通性 |
| 转发建立但无法连接 | 服务端禁用了转发 | 检查服务端 -j / -k 选项 |
调试命令
# 详细输出(调试转发问题)
dbclient -v -L 8080:internal:80 admin@jumphost
# 检查端口监听
ss -tlnp | grep 8080
netstat -tlnp | grep 8080
# 测试隧道连通性
curl -v http://localhost:8080
6.9 业务场景:安全远程运维
完整的远程运维方案
#!/bin/sh
# remote-ops.sh - 基于 SSH 隧道的远程运维方案
JUMPHOST="bastion.example.com"
JUMPUSER="ops"
DEVICE_IP="192.168.1.100"
DEVICE_SSH_PORT="22"
DEVICE_WEB_PORT="80"
# 1. 建立多服务隧道
echo "建立 SSH 隧道..."
dbclient -f -N \
-L 2222:${DEVICE_IP}:${DEVICE_SSH_PORT} \
-L 8080:${DEVICE_IP}:${DEVICE_WEB_PORT} \
-K 30 \
"${JUMPUSER}@${JUMPHOST}"
echo "隧道已建立:"
echo " SSH: localhost:2222"
echo " Web: http://localhost:8080"
echo ""
echo "使用方法:"
echo " dbclient -p 2222 root@localhost"
echo " curl http://localhost:8080"
# 2. 等待用户操作
read -p "按 Enter 关闭隧道..."
pkill -f "dbclient.*${JUMPHOST}"
6.10 本章小结
| 要点 | 说明 |
|---|---|
| 本地转发 (-L) | 将本地端口映射到远程服务 |
| 远程转发 (-R) | 将远程端口映射到本地服务 |
| 动态 SOCKS (-D) | 创建 SOCKS 代理 |
| X11 转发 (-X) | 远程图形界面转发 |
| 保活 | -K 30 防止隧道超时 |
| 后台运行 | -f -N 后台运行不执行命令 |
| 安全 | 服务端可用 -j / -k 禁止转发 |
扩展阅读
上一章:认证方式 | 下一章:SCP 与 SFTP →