udtunnel 项目方案与说明文档

版本: 0.1.0 (基于 Navicat 协议版本 206)

Navicat的官方脚本,做为参考: “_doc/参考/ntunnel_mysql.php”

1. 项目概述

  • 项目名称: udtunnel
  • 目标: 创建一个安全、轻量级、配置驱动的数据库 HTTP/S 隧道,主要服务于需要通过 HTTP(S) 协议间接访问关系型数据库的场景,特别是为了兼容 Navicat 客户端的 HTTP 隧道功能。
  • 初期支持: 优先支持 MySQL / MariaDB。
  • 未来扩展: 设计上考虑支持 PostgreSQL 和 SQLite。

核心特性:

  1. HTTP/HTTPS 隧道: 接收 Navicat 的 HTTP(S) POST 请求,代理执行数据库操作。
  2. Navicat 协议兼容: 实现 Navicat HTTP 隧道二进制协议 (版本 206, mysqli 模式)。
  3. 配置文件驱动: 使用 YAML (config.yaml) 进行配置,支持 -c 参数指定路径。
  4. 可选 TLS: 可配置启用内置 HTTPS 或禁用以配合反向代理。
  5. 隧道认证: 支持 API Key 或 Basic Auth (实现待完成)。
  6. 数据库连接池: 为每个目标维护连接池。
  7. 安全设计: 包含 TLS 支持、认证、目标白名单 (SSRF 防护)、路径限制 (SQLite)。
  8. 单文件部署: 可编译为单个可执行文件。

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 协议代码。

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/httpdatabase/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 指定路径)。务必配置 authallowed_targets!
  • 运行: ./udtunnel./udtunnel -c <path>
  • Navicat 配置 (MySQL/MariaDB):
    1. 新建连接 -> HTTP 选项卡 -> 勾选 “Use HTTP Tunnel”。
    2. Tunnel URL: https://<服务器地址>:<端口>/tunnel?db_type=mysql (注意是 https 还是 http 取决于 tls.enabled 或反向代理配置,必须包含 db_type 参数)。
    3. 认证: 不要勾选 Navicat 的 “Use Authentication”。根据 udtunnelauth.method 在 HTTP Header 中添加 X-Auth-Token (或其他) 或等待 Basic Auth 支持 (当前认证被绕过)。
    4. 常规选项卡: 填写目标数据库的实际连接信息。
    5. 测试连接。

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 测试。
    • 文档: 补充更详细的配置选项说明、安全最佳实践、故障排查。

安全警告: 当前版本绕过了认证逻辑,仅供测试和开发。请勿在生产环境中使用,直至认证和安全检查完全实现并通过测试。