599 lines
20 KiB
Markdown
599 lines
20 KiB
Markdown
# GoTunnel
|
||
|
||
[](https://go.dev/)
|
||
[](LICENSE)
|
||
|
||
一个轻量级、高性能的内网穿透工具,采用服务端集中化管理模式,支持 TLS 加密通信。
|
||
|
||
## 项目简介
|
||
|
||
GoTunnel 是一个类似 frp 的内网穿透解决方案,核心特点是**服务端集中管理配置**和**零配置 TLS 加密**。客户端只需提供认证信息即可自动获取映射规则,无需在客户端维护复杂配置。
|
||
|
||
### 与 frp 的主要区别
|
||
|
||
| 特性 | GoTunnel | frp |
|
||
|------|----------|-----|
|
||
| 配置管理 | 服务端集中管理 | 客户端各自配置 |
|
||
| TLS 证书 | 自动生成,零配置 | 需手动配置 |
|
||
| 管理界面 | 内置 Web 控制台 (naive-ui) | 需额外部署 Dashboard |
|
||
| 客户端部署 | 仅需 2 个参数 | 需配置文件 |
|
||
| 客户端 ID | 可选,服务端自动分配 | 需手动配置 |
|
||
|
||
### 架构设计
|
||
|
||
```
|
||
┌──────────────┐ ┌──────────────────────┐
|
||
│ Client │ Control Channel │ Server │
|
||
│ │ ◄────────────────►│ │
|
||
│ ┌────────┐ │ (Yamux Mux) │ ┌────────────────┐ │
|
||
│ │ Agent │ │ │ │ Control Manager│ │
|
||
│ └────────┘ │ │ └────────────────┘ │
|
||
│ │ │ │ │ │
|
||
│ ▼ │ Data Streams │ ▼ │
|
||
│ ┌────────┐ │ ◄────────────────►│ ┌────────────────┐ │
|
||
│ │ Proxy │ │ │ │ Proxy Listener │ │
|
||
│ └────────┘ │ │ │ :8080,:9090 │ │
|
||
│ │ │ │ └────────────────┘ │
|
||
│ ▼ │ │ ▲ │
|
||
│ ┌────────┐ │ │ │ │
|
||
│ │Local:80│ │ │ External Users │
|
||
│ └────────┘ │ │ │
|
||
└──────────────┘ └──────────────────────┘
|
||
```
|
||
|
||
## 功能特性
|
||
|
||
### 核心功能
|
||
|
||
- **服务端集中管理** - 所有客户端的映射规则由服务端统一配置,客户端零配置
|
||
- **多路复用** - 基于 Yamux 实现控制通道与数据通道分离,高效复用单一 TCP 连接
|
||
- **多客户端支持** - 支持多个客户端同时连接,每个客户端独立的映射规则
|
||
- **端口冲突检测** - 自动检测系统端口占用和客户端间端口冲突
|
||
- **SOCKS5/HTTP 代理** - 支持通过客户端网络访问任意网站
|
||
- **自动更新** - 服务端和客户端支持从 Web 界面一键更新
|
||
|
||
### 安全性
|
||
|
||
- **TLS 加密** - 默认启用 TLS 加密,证书自动生成,零配置
|
||
- **TOFU 证书验证** - 首次连接信任 (Trust On First Use),防止中间人攻击
|
||
- **Token 认证** - 基于 Token 的身份验证机制
|
||
- **强制 Web 认证** - Web 控制台强制启用 JWT 认证
|
||
- **安全审计日志** - 记录所有认证事件和安全相关操作
|
||
- **连接数限制** - 防止资源耗尽攻击 (默认 10000 连接上限)
|
||
- **客户端 ID 验证** - 严格的 ID 格式校验,防止注入攻击
|
||
|
||
### 可靠性
|
||
|
||
- **心跳检测** - 可配置的心跳间隔和超时时间,及时发现断线
|
||
- **断线重连** - 客户端自动重连机制,网络恢复后自动恢复服务
|
||
- **优雅关闭** - 支持 SIGINT/SIGTERM 信号,安全关闭所有连接
|
||
- **资源自动释放** - 客户端断开时自动释放端口资源
|
||
|
||
### Web 管理
|
||
|
||
- **Web 控制台** - 内置 Web 管理界面,可视化管理客户端和规则
|
||
- **实时状态** - 查看客户端在线状态
|
||
- **动态配置** - 在线添加/修改客户端规则
|
||
|
||
## 快速开始
|
||
|
||
### 安装
|
||
|
||
**从源码编译:**
|
||
|
||
```bash
|
||
git clone https://github.com/your-repo/gotunnel.git
|
||
cd gotunnel
|
||
go build -o server ./cmd/server
|
||
go build -o client ./cmd/client
|
||
```
|
||
|
||
**下载预编译二进制:**
|
||
|
||
从 Releases 页面下载对应平台的二进制文件。
|
||
|
||
### 服务端启动
|
||
|
||
```bash
|
||
# 零配置启动(自动生成 Token,启用 TLS 和 Web 控制台)
|
||
./server
|
||
|
||
# 或指定配置文件
|
||
./server -c server.yaml
|
||
```
|
||
|
||
首次启动会自动:
|
||
- 生成随机 Token(打印在日志中)
|
||
- 启用 TLS 加密(证书在内存中自动生成)
|
||
- 启动 Web 控制台(默认 http://localhost:7500)
|
||
- 创建 SQLite 数据库存储客户端配置
|
||
|
||
### 客户端启动
|
||
|
||
```bash
|
||
# 最简启动(ID 由服务端自动分配)
|
||
./client -s <服务器IP>:7000 -t <Token>
|
||
|
||
# 指定客户端 ID
|
||
./client -s <服务器IP>:7000 -t <Token> -id <客户端ID>
|
||
|
||
# 禁用 TLS(需服务端也禁用)
|
||
./client -s <服务器IP>:7000 -t <Token> -no-tls
|
||
```
|
||
|
||
**参数说明:**
|
||
|
||
| 参数 | 说明 | 必填 |
|
||
|------|------|------|
|
||
| `-s` | 服务器地址 (ip:port) | 是 |
|
||
| `-t` | 认证 Token | 是 |
|
||
| `-id` | 客户端 ID | 否(服务端自动分配) |
|
||
| `-no-tls` | 禁用 TLS 加密 | 否 |
|
||
| `-skip-verify` | 跳过证书验证(不安全,仅测试用) | 否 |
|
||
|
||
## 配置系统
|
||
|
||
服务端使用 YAML 配置文件 + SQLite 数据库管理。YAML 配置服务端参数,SQLite 存储客户端规则。
|
||
|
||
### 配置文件示例
|
||
|
||
```yaml
|
||
# server.yaml
|
||
server:
|
||
bind_addr: "0.0.0.0" # 监听地址
|
||
bind_port: 7000 # 监听端口
|
||
token: "your-secret-token" # 认证 Token(不配置则自动生成)
|
||
heartbeat_sec: 30 # 心跳间隔(秒)
|
||
heartbeat_timeout: 90 # 心跳超时(秒)
|
||
db_path: "gotunnel.db" # 数据库路径
|
||
tls_disabled: false # 是否禁用 TLS(默认启用)
|
||
|
||
web:
|
||
enabled: true # 启用 Web 控制台
|
||
bind_addr: "0.0.0.0"
|
||
bind_port: 7500
|
||
username: "admin" # 可选,设置后启用认证
|
||
password: "password"
|
||
```
|
||
|
||
### 配置参数说明
|
||
|
||
**Server 配置:**
|
||
|
||
| 参数 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `bind_addr` | string | 0.0.0.0 | 服务端监听地址 |
|
||
| `bind_port` | int | 7000 | 服务端监听端口 |
|
||
| `token` | string | 自动生成 | 客户端认证 Token |
|
||
| `heartbeat_sec` | int | 30 | 心跳发送间隔(秒) |
|
||
| `heartbeat_timeout` | int | 90 | 心跳超时时间(秒) |
|
||
| `db_path` | string | gotunnel.db | SQLite 数据库路径 |
|
||
| `tls_disabled` | bool | false | 是否禁用 TLS |
|
||
|
||
**Web 配置:**
|
||
|
||
| 参数 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `enabled` | bool | true | 是否启用 Web 控制台 |
|
||
| `bind_addr` | string | 0.0.0.0 | Web 监听地址 |
|
||
| `bind_port` | int | 7500 | Web 监听端口 |
|
||
| `username` | string | - | 认证用户名(可选) |
|
||
| `password` | string | - | 认证密码(可选) |
|
||
|
||
## 代理规则类型
|
||
|
||
通过 Web 控制台配置客户端规则时,支持以下类型:
|
||
|
||
### 内置类型
|
||
|
||
| 类型 | 说明 | 示例用途 |
|
||
|------|------|----------|
|
||
| `tcp` | TCP 端口转发(默认) | SSH、MySQL、Web 服务 |
|
||
| `udp` | UDP 端口转发 | DNS、游戏服务器、VoIP |
|
||
| `http` | HTTP 代理 | 通过客户端网络访问 HTTP/HTTPS |
|
||
| `https` | HTTPS 代理 | 同 HTTP,支持 CONNECT 方法 |
|
||
|
||
| `socks5` | SOCKS5 代理 | 通过客户端网络访问任意地址 |
|
||
|
||
**规则配置示例(通过 Web API):**
|
||
|
||
```json
|
||
{
|
||
"id": "client-a",
|
||
"nickname": "办公室电脑",
|
||
"rules": [
|
||
{"name": "web", "type": "tcp", "local_ip": "127.0.0.1", "local_port": 80, "remote_port": 8080},
|
||
{"name": "dns", "type": "udp", "local_ip": "127.0.0.1", "local_port": 53, "remote_port": 5353},
|
||
{"name": "socks5-proxy", "type": "socks5", "remote_port": 1080},
|
||
{"name": "http-proxy", "type": "http", "remote_port": 8888}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
GoTunnel/
|
||
├── cmd/
|
||
│ ├── server/main.go # 服务端入口
|
||
│ └── client/main.go # 客户端入口
|
||
├── internal/
|
||
│ ├── server/
|
||
│ │ ├── tunnel/ # 隧道服务
|
||
│ │ ├── config/ # 配置管理
|
||
│ │ ├── db/ # 数据库存储
|
||
│ │ ├── app/ # Web 服务
|
||
│ │ ├── router/ # API 路由
|
||
│ │ └── plugin/ # 服务端插件管理
|
||
│ └── client/
|
||
│ ├── tunnel/ # 客户端隧道
|
||
│ └── plugin/ # 客户端插件管理和缓存
|
||
├── pkg/
|
||
│ ├── protocol/ # 通信协议
|
||
│ ├── crypto/ # TLS 加密
|
||
│ ├── proxy/ # 代理服务器
|
||
│ ├── relay/ # 数据转发
|
||
│ ├── auth/ # JWT 认证
|
||
│ ├── utils/ # 工具函数
|
||
│ ├── version/ # 版本信息和更新检查
|
||
│ ├── update/ # 共享更新逻辑 (下载、解压)
|
||
│ └── plugin/ # JS 插件系统核心 (goja)
|
||
│ └── store/ # 插件持久化 (SQLite)
|
||
├── web/ # Vue 3 + naive-ui 前端
|
||
├── scripts/ # 构建脚本
|
||
│ ├── build.sh # Linux/macOS 构建脚本
|
||
│ └── build.ps1 # Windows 构建脚本
|
||
└── go.mod
|
||
```
|
||
|
||
## 插件系统
|
||
|
||
GoTunnel 支持灵活的 JS 插件系统,可扩展代理协议和应用功能。
|
||
|
||
### 插件类型
|
||
|
||
| 类型 | 说明 | 运行位置 |
|
||
|------|------|----------|
|
||
| `app` | 应用插件 (如 HTTP 文件服务、Echo 服务) | 客户端 |
|
||
|
||
### 插件来源
|
||
|
||
- **JS 插件**: 基于 goja 运行时,支持动态加载和热更新
|
||
- **插件商店**: 从服务端管理的插件商店浏览和安装
|
||
|
||
### 开发 JS 插件
|
||
|
||
详细的插件开发文档请参考 [PLUGINS.md](PLUGINS.md)。
|
||
|
||
**快速示例 - Echo 插件:**
|
||
|
||
```javascript
|
||
function metadata() {
|
||
return {
|
||
name: "echo",
|
||
version: "1.0.0",
|
||
type: "app",
|
||
description: "Echo service plugin",
|
||
author: "GoTunnel"
|
||
};
|
||
}
|
||
|
||
function start() {
|
||
log("Echo plugin started");
|
||
}
|
||
|
||
function handleConn(conn) {
|
||
var data = conn.Read(1024);
|
||
if (data) {
|
||
conn.Write(data);
|
||
}
|
||
conn.Close();
|
||
}
|
||
|
||
function stop() {
|
||
log("Echo plugin stopped");
|
||
}
|
||
```
|
||
|
||
## Web API
|
||
|
||
Web 控制台提供 RESTful API 用于管理客户端和配置。配置了 `username` 和 `password` 后,API 需要 JWT 认证。
|
||
|
||
### 认证
|
||
|
||
```bash
|
||
# 登录获取 Token
|
||
POST /api/auth/login
|
||
Content-Type: application/json
|
||
{"username": "admin", "password": "password"}
|
||
|
||
# 响应
|
||
{"token": "eyJhbGciOiJIUzI1NiIs..."}
|
||
|
||
# 后续请求携带 Token
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
### 客户端管理
|
||
|
||
```bash
|
||
# 获取所有客户端
|
||
GET /api/clients
|
||
|
||
# 获取单个客户端
|
||
GET /api/client/{id}
|
||
|
||
# 更新客户端(昵称和规则)
|
||
PUT /api/client/{id}
|
||
Content-Type: application/json
|
||
{"nickname": "办公室电脑", "rules": [...]}
|
||
|
||
# 删除客户端
|
||
DELETE /api/client/{id}
|
||
```
|
||
|
||
### 客户端控制
|
||
|
||
```bash
|
||
# 推送配置到在线客户端(客户端会立即应用新规则)
|
||
POST /api/client/{id}/push
|
||
|
||
# 断开客户端连接
|
||
POST /api/client/{id}/disconnect
|
||
```
|
||
|
||
### 插件管理
|
||
|
||
```bash
|
||
# 获取已注册的插件列表
|
||
GET /api/plugins
|
||
|
||
# 响应示例
|
||
[
|
||
{
|
||
"name": "socks5",
|
||
"version": "1.0.0",
|
||
"description": "SOCKS5 proxy plugin",
|
||
"source": "builtin"
|
||
}
|
||
]
|
||
```
|
||
|
||
### 服务状态
|
||
|
||
```bash
|
||
# 获取服务状态
|
||
GET /api/status
|
||
|
||
# 获取配置
|
||
GET /api/config
|
||
|
||
# 更新配置
|
||
PUT /api/config
|
||
Content-Type: application/json
|
||
{"server": {"heartbeat_sec": 30}, "web": {"enabled": true}}
|
||
|
||
# 重载配置
|
||
POST /api/config/reload
|
||
```
|
||
|
||
## 使用场景
|
||
|
||
### 场景一:暴露内网 Web 服务
|
||
|
||
```bash
|
||
# 服务端配置客户端规则(通过 Web 控制台或 API)
|
||
curl -X POST http://server:7500/api/clients \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"id":"home","rules":[{"name":"web","type":"tcp","local_ip":"127.0.0.1","local_port":80,"remote_port":8080}]}'
|
||
|
||
# 客户端连接
|
||
./client -s server:7000 -t <token> -id home
|
||
|
||
# 访问:http://server:8080 -> 内网 127.0.0.1:80
|
||
```
|
||
|
||
### 场景二:SOCKS5 代理访问内网
|
||
|
||
```bash
|
||
# 配置 SOCKS5 代理规则
|
||
{"name":"proxy","type":"socks5","remote_port":1080}
|
||
|
||
# 使用代理
|
||
curl --socks5 server:1080 http://internal-service/
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
**Q: 客户端连接后如何设置昵称?**
|
||
|
||
A: 在 Web 控制台点击客户端详情,进入编辑模式即可设置昵称。
|
||
|
||
**Q: 如何禁用 TLS?**
|
||
|
||
A: 服务端配置 `tls_disabled: true`,客户端使用 `-no-tls` 参数。
|
||
|
||
**Q: 端口被占用怎么办?**
|
||
|
||
A: 服务端会自动检测端口冲突,请检查日志并更换端口。
|
||
|
||
**Q: 客户端 ID 是如何分配的?**
|
||
|
||
A: 如果客户端未指定 `-id` 参数,服务端会自动生成 16 位随机 ID。
|
||
|
||
**Q: 如何更新服务端/客户端?**
|
||
|
||
A: 在 Web 控制台的"更新"页面,可以检查并应用更新。服务端/客户端会自动从 Release 下载压缩包、解压并重启。
|
||
|
||
## 构建
|
||
|
||
使用构建脚本可以一键构建前后端:
|
||
|
||
**Linux/macOS:**
|
||
|
||
```bash
|
||
# 构建当前平台
|
||
./scripts/build.sh current
|
||
|
||
# 构建所有平台
|
||
./scripts/build.sh all
|
||
|
||
# 仅构建 Web UI
|
||
./scripts/build.sh web
|
||
|
||
# 清理构建产物
|
||
./scripts/build.sh clean
|
||
|
||
# 指定版本号
|
||
VERSION=1.0.0 ./scripts/build.sh all
|
||
```
|
||
|
||
**Windows (PowerShell):**
|
||
|
||
```powershell
|
||
# 构建当前平台
|
||
.\scripts\build.ps1 current
|
||
|
||
# 构建所有平台
|
||
.\scripts\build.ps1 all
|
||
|
||
# 仅构建 Web UI
|
||
.\scripts\build.ps1 web
|
||
|
||
# 清理构建产物
|
||
.\scripts\build.ps1 clean
|
||
|
||
# 指定版本号
|
||
$env:VERSION="1.0.0"; .\scripts\build.ps1 all
|
||
```
|
||
|
||
构建产物输出到 `build/<os>_<arch>/` 目录。
|
||
|
||
## 架构时序图
|
||
|
||
### 1. 连接建立阶段
|
||
|
||
```
|
||
┌────────┐ ┌────────┐ ┌──────────┐
|
||
│ Client │ │ Server │ │ Database │
|
||
└───┬────┘ └───┬────┘ └────┬─────┘
|
||
│ │ │
|
||
│ 1. TCP/TLS Connect│ │
|
||
│──────────────────>│ │
|
||
│ │ │
|
||
│ 2. AuthRequest │ │
|
||
│ {token, id?} │ │
|
||
│──────────────────>│ │
|
||
│ │ 3. 验证 Token │
|
||
│ │ 4. 查询/创建客户端 │
|
||
│ │───────────────────>│
|
||
│ │<───────────────────│
|
||
│ │ │
|
||
│ 5. AuthResponse │ │
|
||
│ {ok, client_id} │ │
|
||
│<──────────────────│ │
|
||
│ │ │
|
||
│ 6. Yamux Session │ │
|
||
│<═════════════════>│ │
|
||
│ │ │
|
||
│ 7. ProxyConfig │ │
|
||
│ {rules[]} │ │
|
||
│<──────────────────│ │
|
||
│ │ │
|
||
```
|
||
|
||
### 2. TCP 代理数据流
|
||
|
||
```
|
||
┌──────────┐ ┌────────┐ ┌────────┐ ┌───────────────┐
|
||
│ External │ │ Server │ │ Client │ │ Local Service │
|
||
└────┬─────┘ └───┬────┘ └───┬────┘ └───────┬───────┘
|
||
│ │ │ │
|
||
│ 1. Connect │ │ │
|
||
│ :remote │ │ │
|
||
│─────────────>│ │ │
|
||
│ │ │ │
|
||
│ │ 2. Yamux │ │
|
||
│ │ Stream │ │
|
||
│ │────────────>│ │
|
||
│ │ │ │
|
||
│ │ 3. NewProxy │ │
|
||
│ │ {port} │ │
|
||
│ │────────────>│ │
|
||
│ │ │ │
|
||
│ │ │ 4. Connect │
|
||
│ │ │ local:port │
|
||
│ │ │────────────────>│
|
||
│ │ │ │
|
||
│ 5. Relay (双向数据转发) │ │
|
||
│<════════════>│<═══════════>│<═══════════════>│
|
||
│ │ │ │
|
||
```
|
||
|
||
### 3. SOCKS5/HTTP 代理数据流
|
||
|
||
```
|
||
┌──────────┐ ┌────────┐ ┌────────┐ ┌─────────────┐
|
||
│ External │ │ Server │ │ Client │ │ Target Host │
|
||
└────┬─────┘ └───┬────┘ └───┬────┘ └──────┬──────┘
|
||
│ │ │ │
|
||
│ 1. SOCKS5 │ │ │
|
||
│ Handshake │ │ │
|
||
│─────────────>│ │ │
|
||
│ │ │ │
|
||
│ │ 2. Proxy │ │
|
||
│ │ Connect │ │
|
||
│ │ {target} │ │
|
||
│ │────────────>│ │
|
||
│ │ │ │
|
||
│ │ │ 3. Dial target │
|
||
│ │ │───────────────>│
|
||
│ │ │ │
|
||
│ │ 4. Result │ │
|
||
│ │<────────────│ │
|
||
│ │ │ │
|
||
│ 5. Relay (双向数据转发) │ │
|
||
│<════════════>│<═══════════>│<══════════════>│
|
||
│ │ │ │
|
||
```
|
||
|
||
### 4. 心跳保活机制
|
||
|
||
```
|
||
┌────────┐ ┌────────┐
|
||
│ Client │ │ Server │
|
||
└───┬────┘ └───┬────┘
|
||
│ │
|
||
│ │ 1. Ticker (30s)
|
||
│ │
|
||
│ 2. Heartbeat │
|
||
│<──────────────────│
|
||
│ │
|
||
│ 3. HeartbeatAck │
|
||
│──────────────────>│
|
||
│ │
|
||
│ │ 4. 更新 LastPing
|
||
│ │
|
||
│ ... 循环 ... │
|
||
│ │
|
||
│ │ 5. 超时检测 (90s)
|
||
│ │ 无响应则断开
|
||
│ │
|
||
```
|
||
|
||
### 核心组件说明
|
||
|
||
| 组件 | 职责 |
|
||
|------|------|
|
||
| Client | 连接服务端、转发本地服务、响应心跳 |
|
||
| Server | 认证、管理会话、监听端口、路由流量 |
|
||
| Yamux | 单连接多路复用,承载控制和数据通道 |
|
||
| Plugin | 处理 SOCKS5/HTTP 等代理协议 |
|
||
| PortManager | 端口分配与释放管理 |
|
||
| Database | 持久化客户端配置和规则 |
|
||
|
||
## 许可证
|
||
|
||
本项目采用 [MIT License](LICENSE) 开源许可证。
|
||
|