apppublic/aidocs/port_forward.md
2025-10-05 11:23:33 +08:00

7.8 KiB
Raw Blame History

SSH 端口转发工具技术文档

概述

本项目实现了一个基于 Paramiko 的 SSH 端口转发Port Forwarding客户端支持通过 SSH 隧道将本地端口映射到远程目标主机和端口。该工具可用于安全地访问内网服务或绕过防火墙限制。

主要功能:

  • 建立 SSH 连接到跳板机SSH Server
  • 在本地监听指定端口
  • 将所有连接通过 SSH 隧道转发至目标主机remote_host:remote_port
  • 支持动态配置、后台运行与手动启停控制

依赖库

库名 用途
paramiko 实现 SSH 客户端连接与通道管理
socket 网络通信、地址解析
select I/O 多路复用,用于双向数据转发
SocketServer / socketserver 构建 TCP 服务器以监听本地端口(兼容 Python 2/3
appPublic.background.Background 后台线程执行任务

⚠️ 注意:需确保已安装 paramikoappPublic 包。

pip install paramiko

核心类说明

1. ForwardServer —— 多线程 TCP 服务器

继承自 SocketServer.ThreadingTCPServer,用于在本地监听端口并接受入站连接。

特性

  • daemon_threads = True:子线程随主线程退出而终止。
  • allow_reuse_address = True:允许重用本地地址(避免端口占用问题)。
  • server_ready:标志服务器是否已启动完成。
  • ready_callback:服务器就绪时调用的回调函数。

方法

方法 说明
service_actions() 重写父类方法,在首次服务启动后触发 ready_callback 回调
shutdown() 关闭服务器,并重置 server_ready 状态

2. Handler —— 请求处理器

继承自 SocketServer.BaseRequestHandler,处理每一个来自客户端的连接请求。

属性(动态绑定)

  • ssh_transportSSH 传输通道(由外部注入)
  • chain_host:目标主机地址(远程实际服务地址)
  • chain_port:目标主机端口

工作流程

  1. 尝试通过 SSH 创建 direct-tcpip 类型的隧道通道
  2. 若失败,打印错误日志并返回
  3. 成功后进入循环:
    • 使用 select.select() 监听本地 socket 与 SSH channel 的可读事件
    • 双向转发数据(本地 ↔ SSH 隧道)
  4. 任一端关闭连接时,清理资源并输出关闭信息

日志输出示例

Connected! Tunnel open ('127.0.0.1', 50000) -> ('192.168.1.10', 22) -> ('10.0.0.5', 80)
Tunnel closed from ('127.0.0.1', 50000)

3. SSHPortForward —— 主控制器类

封装完整的 SSH 端口转发逻辑,提供简洁的接口用于启动/停止服务。

构造函数参数

参数 类型 描述
local_port int 本地监听端口(如 8080
remote_host str 目标主机域名或 IP通过 SSH 跳转访问的目标)
remote_port int 目标主机端口
ssh_host str SSH 服务器地址(跳板机)
ssh_port int SSH 服务端口(通常为 22
ssh_user str SSH 登录用户名
ssh_password str SSH 登录密码

内部属性

属性 类型 描述
self.running bool 当前服务是否正在运行
self._ready bool 服务是否已准备就绪(可用于健康检查)
self.ssh SSHClient Paramiko SSH 客户端实例
self.transport Transport SSH 传输层对象
self.forward_server ForwardServer 本地监听服务器实例

公共方法

run()

启动端口转发服务(异步非阻塞)。若已在运行,则忽略。

内部使用 Background 类在新线程中执行 _run()

_run()

私有方法,运行于后台线程:

  1. 连接 SSH 服务器(connect_ssh_server()
  2. 获取 SSH 传输通道
  3. 动态创建 MyForwardServer 子类以设置回调
  4. 动态创建 SubHandler 并注入 chain_host, chain_port, ssh_transport
  5. 绑定到 localhost:local_port 并开始监听(serve_forever()
stop()

停止当前运行的服务:

  • 调用 forward_server.shutdown()
  • 关闭 server socket
  • 断开 SSH 连接transport 和 client
service_ready()

回调函数,当本地服务器成功启动后被调用,打印提示信息并将 _ready 设为 True


4. 辅助函数

connect_ssh_server(host, port, user, password)

建立 SSH 连接并返回 SSHClient 实例。

  • 自动添加未知主机密钥(AutoAddPolicy
  • 返回已连接的 SSH 客户端

verbose(s)

条件性打印调试信息,受全局变量 g_verbose 控制。

默认开启(g_verbose = True),可设为 False 关闭日志输出。


使用方式

命令行模式(主程序入口)

当直接运行脚本时,进入交互式控制台。

启动命令格式

python ssh_forward.py <本地端口> <目标主机> <目标端口> <SSH主机> <SSH端口> <SSH用户> <SSH密码>

示例

python ssh_forward.py 8888 example.internal 80 gateway.example.com 22 alice mypass123

此命令表示:

所有发往本机 8888 端口的流量,将通过 gateway.example.com 的 SSH 隧道,转发至 example.internal:80

交互命令

程序启动后会显示菜单:

start) start server,
stop) stop server
quit) quit

输入对应指令即可操作服务状态。


工作原理图解

+-------------+       +------------------+       +--------------------+
|             |       |                  |       |                    |
|  Client     | ----> | Local Listener   | ----> | SSH Tunnel         | ----> Target Service
| (e.g. curl) |       | (SSHPortForward) |       | (via ssh_host)     |
|             |       |                  |       |                    |
+-------------+       +------------------+       +--------------------+
                          ↑
                      localhost:8888
  1. 用户访问 http://localhost:8888
  2. SSHPortForward 接收连接
  3. 通过 SSH 隧道建立到 remote_host:remote_port 的 direct-tcpip 通道
  4. 数据双向透明转发

错误处理与日志

  • 所有异常均被捕获并输出详细信息(通过 verbose()
  • 常见错误包括:
    • SSH 认证失败
    • 目标主机无法解析DNS
    • SSH 服务器拒绝端口转发请求
    • 网络中断导致连接关闭

建议生产环境根据需要关闭 g_verbose 或重定向日志。


安全注意事项

  1. 密码明文存储:当前版本在内存中保存明文密码,不适用于高安全场景。建议扩展支持密钥认证(.pem 文件)。
  2. 无加密本地通信:本地监听仅限 localhost,防止外部访问敏感端口。
  3. 自动信任主机密钥:使用 AutoAddPolicy(),存在中间人攻击风险。生产环境应验证主机指纹。

扩展建议

功能 描述
支持私钥登录 添加 pkey 参数,替代密码认证
配置文件支持 使用 JSON/YAML 加载配置,避免命令行长参数
REST API 控制 提供 HTTP 接口进行 start/stop 操作
日志模块替换 使用标准 logging 模块代替 print
多隧道支持 管理多个并发转发规则
超时与心跳机制 防止长时间空闲断连

示例代码调用

# 编程方式使用
tunnel = SSHPortForward(
    local_port=9000,
    remote_host="internal.db",
    remote_port=3306,
    ssh_host="jumpbox.company.com",
    ssh_port=22,
    ssh_user="dev",
    ssh_password="secret"
)

tunnel.run()  # 启动
# ... 使用一段时间 ...
tunnel.stop()  # 停止

版权与许可

  • 作者:未知(请补充)
  • 依赖开源库Paramiko (LGPL), Python 标准库
  • 使用遵循相应许可证要求

文档版本v1.0
📅 最后更新2025-04-05