udtunnel 项目方案与说明文档
版本: 0.1.0 (基于 Navicat 协议版本 206)
Navicat的官方脚本,做为参考: “_doc/参考/ntunnel_mysql.php”
1. 项目概述
- 项目名称: udtunnel
- 目标: 创建一个安全、轻量级、配置驱动的数据库 HTTP/S 隧道,主要服务于需要通过 HTTP(S) 协议间接访问关系型数据库的场景,特别是为了兼容 Navicat 客户端的 HTTP 隧道功能。
- 初期支持: 优先支持 MySQL / MariaDB。
- 未来扩展: 设计上考虑支持 PostgreSQL 和 SQLite。
核心特性:
- HTTP/HTTPS 隧道: 接收 Navicat 的 HTTP(S) POST 请求,代理执行数据库操作。
- Navicat 协议兼容: 实现 Navicat HTTP 隧道二进制协议 (版本 206,
mysqli
模式)。 - 配置文件驱动: 使用 YAML (
config.yaml
) 进行配置,支持-c
参数指定路径。 - 可选 TLS: 可配置启用内置 HTTPS 或禁用以配合反向代理。
- 隧道认证: 支持 API Key 或 Basic Auth (实现待完成)。
- 数据库连接池: 为每个目标维护连接池。
- 安全设计: 包含 TLS 支持、认证、目标白名单 (SSRF 防护)、路径限制 (SQLite)。
- 单文件部署: 可编译为单个可执行文件。
2. 系统架构
udtunnel
采用请求-处理-响应模型,通过中间件处理通用逻辑。
graph LR subgraph "客户端 (Navicat)" N[Navicat Client] end subgraph "网络传输" TlsProxy{反向代理 (Nginx)\n处理 TLS (可选)} InternalHttp[内部 HTTP/S 通信] end subgraph "udtunnel 服务" HttpServer[Go net/http Server] MiddlewareChain[中间件链\n(Log -> Auth -> Sec)] RequestHandler[主处理器 (tunnelHandler)] DbManager[DB 连接管理器 (连接池)] ProtocolEncoder[Navicat 协议编码器] ConfigLoader[配置加载器 (Viper)] Logger[日志记录器] end subgraph "目标数据库" MySQL[MySQL / MariaDB] PostgreSQL[PostgreSQL (未来)] SQLite[SQLite (未来)] end %% 连接 %% N -- HTTPS POST /tunnel?db_type=... --> TlsProxy / HttpServer TlsProxy -- HTTP POST /tunnel?db_type=... --> HttpServer HttpServer -- Request --> MiddlewareChain --> RequestHandler RequestHandler -- DB 操作 --> DbManager --> MySQL MySQL -- 结果 --> DbManager --> RequestHandler RequestHandler -- 编码 --> ProtocolEncoder --> HttpServer HttpServer -- Response --> N / TlsProxy ConfigLoader -- 加载 config.yaml --> HttpServer & 其他组件 所有组件 -- 日志 --> Logger
架构说明:
- 客户端 (Navicat): 发送 POST 请求至
/tunnel
,URL 参数包含db_type
。 - 网络传输: 支持直接 HTTPS 或通过反向代理 (HTTP)。
- udtunnel 服务:
- HTTP Server: 监听端口,处理 HTTP/S 请求,管理连接。
- 配置加载器: 读取
config.yaml
。 - 日志记录器: 记录事件和错误。
- 中间件链:
loggingMiddleware
: 记录请求概要。authMiddleware
: (待实现) 验证请求身份。securityMiddleware
: 添加安全头(SSRF/路径检查当前在 Handler 内)。
- 主请求处理器 (
tunnelHandler
):- 解析 Navicat 参数。
- 执行内联安全检查 (
allowed_targets
,allowed_sqlite_paths
)。 - 调用
DbManager
获取数据库连接。 - 处理 Navicat
actn
("C"
连接测试,"Q"
查询)。 - 调用
ProtocolEncoder
编码响应。
- 数据库连接管理器 (
DBManager
):- 管理
*sql.DB
连接池。 - 提供 DSN 构建和数据库信息获取功能。
- 管理
- Navicat 协议编码器 (
protocol.go
):- 实现 Navicat 二进制协议的
write*
函数。 - 核心:
mapColumnToNavicat
函数,负责将database/sql
列类型精确映射到 Navicat 协议代码。
- 实现 Navicat 二进制协议的
3. 项目结构与文件职责
udtunnel/
├── go.mod # Go 模块文件
├── go.sum # 依赖校验和
├── main.go # 程序入口, 初始化, 服务启动/关闭, 触发配置加载
├── config.go # 配置结构体定义, 配置文件加载与验证 (Viper)
├── db.go # 数据库连接管理(DBManager), DSN构建, getInfo
├── protocol.go # Navicat 协议编码实现, mapColumnToNavicat (核心映射)
├── handlers.go # HTTP 主请求处理逻辑 (tunnelHandler), 内联安全检查
├── middleware.go # HTTP 中间件 (日志, 认证[桩], 安全头)
├── config.yaml.example # 示例配置文件
└── README.md # 项目说明, 配置指南, 安全警告
main.go
: 程序的入口点,负责组装所有组件并启动服务。config.go
: 定义配置结构,并使用 Viper 库加载和验证config.yaml
文件。db.go
: 封装与数据库交互的逻辑,特别是连接池管理和 DSN 构建。protocol.go
: 实现 Navicat HTTP 隧道协议的二进制编码细节,是兼容性的关键。handlers.go
: 包含处理/tunnel
端点请求的核心业务逻辑。middleware.go
: 提供可插拔的请求处理层,用于日志、认证、安全等横切关注点。
4. 设计方案关键点
- 配置驱动: 使用 YAML 配置文件 (
config.yaml
) 集中管理所有可调参数,提供-c
命令行选项指定路径。 - TLS 灵活性: 通过
tls.enabled
配置项支持内置 HTTPS 或依赖外部反向代理。 - 模块化: 代码按功能拆分到不同文件,提高可读性和可维护性。
- 标准化接口: 使用 Go 标准
net/http
和database/sql
接口。 - 协议精确性:
protocol.go
严格按照 Navicat PHP 脚本 (v206, mysqli) 实现二进制格式和类型映射(当前聚焦 MySQL)。 - 安全性:
- 传输层: 强制或推荐 TLS。
- 认证层: (待实现) 支持 API Key / Basic Auth。
- 访问控制:
allowed_targets
(网络) 和allowed_sqlite_paths
(本地文件) 白名单机制,默认拒绝。 - 资源管理: HTTP 超时设置;数据库连接池限制。
- 性能: 连接池复用;并发请求处理;SELECT 结果流式传输。
- 错误处理: 尝试将数据库错误映射到 Navicat 错误码;记录详细日志。
5. 配置文件 (config.yaml
) 详解
# udtunnel 配置文件示例
listen_addr: ":8080" # udtunnel 监听的地址和端口
tls:
enabled: false # 是否启用内置 TLS (HTTPS)
cert_path: "cert.pem" # TLS 证书文件路径 (enabled: true 时必须)
key_path: "key.pem" # TLS 私钥文件路径 (enabled: true 时必须)
auth:
method: "apikey" # 认证方法: "apikey" 或 "basic" (必须配置)
# value: "key1,key2" # API Key 列表,逗号分隔
value: "user:bcrypt_hash" # Basic Auth 用户名和 bcrypt 哈希值
# 允许连接的目标数据库主机/IP/CIDR (SSRF 防护)
# 留空表示拒绝所有网络数据库连接 (推荐默认)
allowed_targets:
- "localhost"
- "127.0.0.1"
# 允许访问的 SQLite 数据库文件绝对路径前缀
# 留空表示拒绝所有 SQLite 连接
allowed_sqlite_paths: []
# 数据库连接池设置
database_pool:
max_open_conns: 10 # 最大打开连接数
max_idle_conns: 5 # 最大空闲连接数
conn_max_lifetime: "1h" # 连接最大可复用时长
# HTTP 服务器超时设置
timeouts:
read: "30s" # 读取请求头+体的最大时间
write: "90s" # 写入响应的最大时间 (允许长查询)
idle: "120s" # Keep-Alive 连接空闲超时
# 日志级别: debug, info, warn, error
log_level: "info"
6. 使用说明
- 编译:
go mod tidy && go build -o udtunnel .
- 配置: 创建并修改
config.yaml
(或使用-c
指定路径)。务必配置auth
和allowed_targets
! - 运行:
./udtunnel
或./udtunnel -c <path>
- Navicat 配置 (MySQL/MariaDB):
- 新建连接 -> HTTP 选项卡 -> 勾选 “Use HTTP Tunnel”。
- Tunnel URL:
https://<服务器地址>:<端口>/tunnel?db_type=mysql
(注意是https
还是http
取决于tls.enabled
或反向代理配置,必须包含db_type
参数)。 - 认证: 不要勾选 Navicat 的 “Use Authentication”。根据
udtunnel
的auth.method
在 HTTP Header 中添加X-Auth-Token
(或其他) 或等待 Basic Auth 支持 (当前认证被绕过)。 - 常规选项卡: 填写目标数据库的实际连接信息。
- 测试连接。
7. 当前状态与后续开发
- 已实现:
- 基于配置文件的启动和可选 TLS。
- 基本的 HTTP 服务和中间件结构。
- 数据库连接池管理。
- Navicat 协议的基本框架 (v206)。
- 针对 MySQL/MariaDB 的协议编码和
mapColumnToNavicat
实现。 - 基本的
allowed_targets
检查。
- 待实现/完善:
middleware.go
: 实现authMiddleware
中的实际认证逻辑 (API Key / Basic Auth + bcrypt)。middleware.go
/handlers.go
: 完善或移动 SSRF/路径验证逻辑,考虑添加速率限制。protocol.go
: 研究、实现并测试 PostgreSQL 和 SQLite 的mapColumnToNavicat
映射。db.go
: 添加 PostgreSQL 和 SQLite 的getInfo
实现和 DSN 调整。- 错误处理: 更细致的错误码映射。
- 日志: 实现基于
log_level
的过滤,考虑使用结构化日志库 (slog
)。 - 测试: 编写单元测试和集成测试,进行跨数据库的手动 Navicat 测试。
- 文档: 补充更详细的配置选项说明、安全最佳实践、故障排查。
安全警告: 当前版本绕过了认证逻辑,仅供测试和开发。请勿在生产环境中使用,直至认证和安全检查完全实现并通过测试。