# WinTunnel 2.3

Windows 内网穿透 + 用户授权管理系统。**主服务端、节点服务器和客户端是三个独立的桌面程序**：

| 程序 | 用途 |
| --- | --- |
| `WinTunnelServer.exe` | 主服务端：用户/卡密/节点管理、登录注册、授权 API |
| `WinTunnelNode.exe` | 节点服务器：部署在各地公网机器，承载实际的隧道流量 |
| `WinTunnelClient.exe` | 内网电脑登录、机器绑定、卡密充值、选择节点、建立隧道 |

三个程序都是无边框深色未来感界面，运行不需要安装 Python 或第三方运行库。

![服务端总览](artifacts/v2-server-overview.png)

![客户端节点地图](artifacts/v2-client-nodes.png)

---

## 先说明部署前提

主服务端需要能被客户端访问（通常只需开放 API 端口 `7100`）；每个节点服务器需要公网可达，并开放自己的控制端口和公网端口范围。控制端口与公网端口都需要同时放行 **TCP 和 UDP**：TCP 用于回退连接和 TCP 服务，UDP 用于 QUIC 控制通道和 UDP 游戏转发。

公网访问满足任意一种：

1. 有公网 IP（云服务器、带公网 IP 的 Windows 主机）；
2. 在路由器/光猫上把 TCP 端口映射到它；
3. 只在局域网内使用，客户端填主服务端/节点局域网 IP。

如果主服务端或节点处于运营商 CGNAT 后面，且无法做端口映射，纯软件无法让公网直接访问，需要一台有公网 IP 的 VPS 中转。

---

## 功能

- 服务端/节点/客户端分离，三个独立 EXE
- 主服务端负责登录、注册、授权、卡密和节点管理；节点服务器承载隧道
- 节点管理：添加/编辑/禁用节点、生成节点令牌、查看在线状态和负载
- 节点自动上报公网 IP，主服务端自动反查经纬度并更新地图位置
- 节点配置一键导入：主服务端复制配置，节点程序自动填表
- 客户端节点选择：中国地图轮廓、节点列表、客户端 IP 地理位置标记
- 节点故障或离线时可切换到其他节点
- 无边框、深空青蓝风格 UI，自绘标题栏、拖动、缩放；客户端不提供最大化，最小化直接收进任务栏
- 服务端直接进入控制台，**不需要账号登录**
- **客户端下载权限**：官网不公开安装包；会员有效期内登录用户中心后才能下载，到期账号返回 403
- 用户管理：新增、重置密码、启用/禁用、续期、删除、解绑机器
- 用户多选/全选、批量加时间、当前连接信息查看
- 机器码封禁/解封：封禁后该机器无法登录或建立隧道
- 卡密管理：批量生成 **20 位大小写字母 + 数字** 卡密、导出 CSV、作废
- 用户充值：客户端输入卡密自动累加天数；管理员也可为指定用户兑换
- **卡密注册**：客户端可用未使用的卡密直接注册新用户并自动登录
- **客户端重置机器码**：左下角“↻ 重置机器码”，扣除 3 天使用时间；服务端管理员解绑不扣时间
- **记住账号密码**：密码用 Windows DPAPI 加密保存，可随时取消
- 机器绑定：物理硬盘序列号、主板序列号、默认网卡 MAC、默认网关 MAC
- 客户端机器码缓存：第二次启动直接加载，后台刷新，不再等待 PowerShell 采集
- 客户端最小化到 Windows 通知区，双击图标恢复，右键可退出
- 客户端节点地图固定尺寸/固定缩放，不再在启动时反复放大
- **自动端口分配**：账号有效期内由所选节点独占分配一个公网端口；到期或禁用后自动释放
- **TCP + UDP 双协议转发**：同一个公网端口同时支持 TCP 服务和 UDP 游戏流量
- **QUIC 优先传输**：控制通道优先走 QUIC/UDP，失败时自动回退 TCP
- **节点列表排序**：支持自动排序（在线优先、低负载、名称）和手动上移/下移，顺序持久化并同步到客户端节点列表
- 所有隧道 socket 启用 `TCP_NODELAY`，降低交互延迟
- 登录使用挑战应答（HMAC），不在网络上传输明文密码
- 客户端登录成功后自动检查版本，下载、SHA-256 校验并静默替换自身
- 服务端可发布客户端版本、设置强制更新、查看版本历史
- 隧道令牌使用登录会话令牌，不再是全局固定密码
- 心跳检测、断线自动重连、并发多流复用

不支持：UDP、TLS、HTTP 层鉴权。详见[安全说明](#安全说明)。

---

## 快速开始

### 1. 启动服务端

1. 运行 `WinTunnelServer.exe`，直接进入“总览”，无需账号登录。
2. 确认参数：

   | 参数 | 默认 | 说明 |
   | --- | --- | --- |
   | 管理 API 端口 | `7100` | 客户端登录、注册、节点列表、授权 |
   | 公网地址 | 留空 | 供节点程序填写主服务端 API 地址 |

3. 点右上角 **启动服务**。
4. 防火墙只放行主服务端 API 端口 `7100` 即可；隧道端口在节点服务器上开放。

```powershell
netsh advfirewall firewall add rule name="WinTunnel API" dir=in action=allow protocol=TCP localport=7100
netsh advfirewall firewall add rule name="WinTunnel Admin" dir=in action=allow protocol=TCP localport=6688
```

### 网页管理后台

启动服务后，浏览器访问：

```text
http://服务器IP:6688
```

初始管理员：

```text
账号：fz524
密码：lfz990524
```

后台支持：运行概览、用户管理、节点管理、卡密管理、操作日志。管理员密码使用 PBKDF2 verifier 存储，不保存明文；首次启动会初始化账号，之后修改密码不会被重启覆盖。

> 6688 是明文 HTTP 管理端口，建议只对可信 IP 放行，或在宝塔/Nginx 前面加 HTTPS 反向代理。不要把 6688 直接暴露到公网。

### 2. 添加节点

主服务端左侧进入 **节点管理**：

1. 点“+ 添加节点”。
2. 填写节点名称、区域、公网地址、控制端口、公网端口范围，以及地图上的经纬度。
3. 创建成功后会弹出节点配置并自动复制：
   - 主服务端 API 地址
   - 节点 ID
   - 节点令牌
   - 控制端口
   - 端口范围
4. 把配置保存好；节点程序需要这些信息才能上线。
5. 在节点服务器点 **“一键导入主服务端”**，会自动读取剪贴板中的节点配置并填好主服务端地址、节点 ID、令牌、端口和端口范围。

> 主服务端的“公网地址”建议填写节点能访问到的公网 IP 或域名；如果留空，导入码会使用 `127.0.0.1`，只适合本机测试。

![服务端节点管理](artifacts/v2-server-nodes.png)

### 3. 启动节点服务器

在每台公网节点机器上：

1. 运行 `WinTunnelNode.exe`。
2. 填写主服务端 API 地址、节点 ID、节点令牌。
3. 填写节点本机控制端口和公网端口范围，必须与主服务端“节点管理”中的配置一致。
4. “节点公网地址”可以留空：节点启动后会自动获取公网 IP，主服务端会反查经纬度并更新节点在地图上的位置；如果手动填写了 IP 或域名，会保留填写内容，节点心跳不会覆盖，客户端“节点入口”按填写值显示。
5. 点“启动节点”。
6. 防火墙同时放行控制端口和公网端口范围的 **TCP + UDP**。

```powershell
netsh advfirewall firewall add rule name="WinTunnel Node Control TCP" dir=in action=allow protocol=TCP localport=7000
netsh advfirewall firewall add rule name="WinTunnel Node Control UDP" dir=in action=allow protocol=UDP localport=7000
netsh advfirewall firewall add rule name="WinTunnel Node Public TCP" dir=in action=allow protocol=TCP localport=8000-9000
netsh advfirewall firewall add rule name="WinTunnel Node Public UDP" dir=in action=allow protocol=UDP localport=8000-9000
```

UDP 规则用于 QUIC 控制连接和 UDP 游戏转发；只放行 TCP 会导致客户端回退到 TCP，UDP 访客无法连接。

节点启动后，主服务端“节点管理”会显示 **在线**，客户端节点地图会变绿。

![节点服务器](artifacts/v2-node.png)

### 4. 创建用户和卡密

服务端左侧进入 **用户管理**：

- “+ 新增用户”：设置用户名、初始密码、初始天数。
- 用户首次登录时自动绑定机器码。
- “卡密充值”：输入卡密给选中用户加天数。
- “解绑机器”：用户换电脑/换硬件后，由管理员免费解绑。
- 用户列表支持 **Ctrl/Shift 多选**，也可以点“全选”，再点“批量加时间”统一续期。
- “连接信息”：查看选中账号当前连接的节点、公网端口、客户端 IP、客户端标识和连接时间。
- “封禁机器码”：封禁选中用户当前绑定的机器码，该机器之后无法登录或建立隧道；“解封机器码”可恢复。
- 用户列表会显示服务端自动分配的端口；用户到期、被禁用或删除后端口自动释放。

进入 **卡密管理**：

- 设置数量、天数、备注，点“生成卡密”。
- 生成后弹窗展示卡密，可一键复制全部。
- 卡密是 20 位大小写字母 + 数字，区分大小写，一次性使用。
- 可“复制选中”“导出 CSV”“作废未使用”。

### 5. 客户端登录

1. 在内网电脑运行 `WinTunnelClient.exe`。
2. 客户端启动时自动采集本机硬件指纹，界面不显示机器码。
3. 填写：
   - 用户名、密码：管理员在服务端创建的账号，或使用卡密自助注册
   - 服务端地址已内置为 `server.cheat.lat:7100`，用户不需要填写
4. 可勾选“记住账号密码”：密码用当前 Windows 用户的 DPAPI 加密保存。
5. 点“验证并登录”。

没有账号时，点 **“没有账号？卡密注册”**，填写用户名、密码和一张未使用的 20 位卡密。注册成功后会自动绑定本机、登录，并消耗该卡密；卡密天数就是新账号的初始授权时长。

![客户端卡密注册](artifacts/v2-client-register.png)

登录成功后：

- 服务端校验账号、密码、启用状态、到期时间、机器码绑定。
- 客户端自动检查版本；有新版本会下载并替换自身，然后重启。
- 进入控制台，默认打开 **节点选择**。

#### 选择节点

- 中国地图轮廓上显示所有节点，**绿色在线、红色离线**。
- 地图上的琥珀色标记是客户端公网 IP 的粗略位置；顶部显示 IP 和地区。
- 点击地图节点或右侧列表，再点 **“使用选中节点”**。
- 服务端会为账号在该节点分配一个端口，并返回节点连接票据。
- 切换节点会自动断开当前隧道，旧节点端口释放。
- 节点离线时会提示选择其他节点。
- 客户端 IP 定位需要主服务端能访问 `ip-api.com`；无法联网时仍会显示 IP，但地图位置显示“位置未知”。
- 主服务端地址、控制端 IP 不在客户端界面显示。
- 隧道控制页显示所选节点的真实 `IP:公网端口`，方便直接发给朋友；可点“复制”复制完整入口。
- 说明：客户端技术上必须知道节点地址才能连接，界面隐藏只能减少截图暴露，不能阻止逆向分析。

![客户端节点选择](artifacts/v2-client-nodes.png)

#### 重置机器码

- 客户端登录后，左下角 **“↻ 重置机器码”** 按钮位于“退出登录”上方。
- 点击后会清空本机绑定并扣除 3 天使用时间，当前隧道断开，账号可在另一台电脑重新登录。
- 剩余时间不足 3 天时，客户端自助重置会被拒绝；请联系管理员在服务端解绑。
- 服务端“用户管理 → 解绑机器（免费）”**不扣除使用时间**。

### 6. 建立隧道

客户端“隧道控制”页：

| 参数 | 示例 | 说明 |
| --- | --- | --- |
| 本地服务 | `127.0.0.1:3389` | 要暴露的内网服务 |
| 公网端口 | 服务器分配 | 有效期内自动分配，到期/禁用后释放 |

公网端口由所选节点自动分配，客户端不能自行指定。同一个账号在有效期内会持续使用同一个节点端口；断开重连不会改变端口。授权到期后端口自动释放，续费后重新选择节点会重新分配。

点“建立隧道”。上线后公网入口显示为：

```text
节点公网IP:8000
```

访问方式：

- 网站：`http://节点IP:8000`
- 远程桌面：`mstsc /v:节点IP:8000`
- SSH：`ssh -p 8000 user@服务端IP`
- 数据库：连接 `服务端IP:8000`

### 5. 充值

客户端“卡密充值”页输入 20 位卡密，点“立即充值”。充值天数会累加到当前到期时间；到期后“建立隧道”按钮会被禁用，充值后恢复。

管理员也可以在“用户管理 → 卡密充值”中直接为某个用户兑换。

### 6. 发布客户端更新

服务端进入 **版本分发**：

1. 填写版本号，例如 `2.0.1`。
2. 选择新的客户端 exe。
3. 填说明，选择是否强制更新。
4. 点“发布更新”。

之后客户端登录成功时会请求 `/api/client/update`：

- 发现更高版本 → 下载到本地 → SHA-256 校验 → 启动临时替换脚本 → 重启新版本。
- 源码模式运行（`python WinTunnelClient.pyw`）只下载不替换，避免破坏开发环境。

> 客户端现在默认发布单文件版 `WinTunnelClient.exe`，不需要 `_internal` 目录。单文件版首次启动会把运行库解压到系统临时目录，启动会比目录版慢约 1～2 秒；这是 PyInstaller onefile 的正常行为。

---

## 架构

```text
                    管理 API :7100（HTTP）
  ┌────────────────┐ ◄──────────────────────────────► ┌──────────────────┐
  │ 主服务端         │   登录 / 注册 / 充值 / 节点列表    │ Windows 客户端    │
  │ 用户/卡密/节点   │   节点票据                        │ 登录 + 机器绑定    │
  │ SQLite 数据库    │                                  │ 选择节点           │
  └───────┬────────┘                                  └────────┬─────────┘
          │ 节点心跳 :7100                                      │ 控制连接 :7000
          ▼                                                     ▼
  ┌────────────────┐   票据校验 + 公网监听 :8000      ┌──────────────────┐
  │ 节点服务器 A     │ ◄══════════════════════════════ │ 节点服务器 B       │
  │ WinTunnelNode   │      会话令牌 + 多路复用 TCP 流    │ WinTunnelNode     │
  └───────┬────────┘                                  └────────┬─────────┘
          │ 访客 TCP :8000                                      │ TCP
          ▼                                                     ▼
    浏览器 / mstsc / ssh                              127.0.0.1:80 / :3389 / :22
```

主服务端只保存用户、卡密、节点和票据，不监听隧道端口；客户端从节点列表中选择一个节点，再由该节点承载实际流量。

登录与选节点流程：

1. 客户端算硬件指纹 → `POST /api/auth/challenge` 获取 salt + nonce。
2. 客户端用 PBKDF2 派生 verifier，再对 `nonce + 用户名 + 机器码` 做 HMAC。
3. `POST /api/auth/login` 提交 proof、机器码、各硬件分量哈希；主服务端校验并签发 24 小时会话令牌。
4. 客户端 `POST /api/nodes` 获取节点列表和客户端 IP 地理位置。
5. 客户端 `POST /api/tunnel/connect` 选择节点；主服务端分配该节点端口，并签发带有效期的节点票据。
6. 客户端用票据连接节点控制端口；节点用节点令牌验证 HMAC 票据，不需要回源主服务端。
7. 节点授权到期时关闭隧道并释放公网端口。

### 机器码

客户端采集：

- 物理硬盘 `Win32_DiskDrive.SerialNumber`
- 主板 `Win32_BaseBoard.SerialNumber`
- 默认网卡 `Win32_NetworkAdapterConfiguration.MACAddress`
- 默认网关 IP 对应的 ARP/邻居表 MAC

每项做 SHA-256，再组合成最终 64 位机器码。上传给服务端的只有各项哈希和最终机器码，不上传原始序列号。

读取失败的项会使用 Windows `MachineGuid` 或网卡节点信息回退；界面会显示 `FALLBACK`。更换硬件、换网卡、换路由器或切换网络导致网关 MAC 变化时，机器码会变化，需要管理员“解绑机器”。

### 卡密

- 格式：`[A-Za-z0-9]{20}`，区分大小写。
- 数据库保存明文卡密，便于管理员查看、导出、复制；请保管好服务端数据库。
- 一次性使用；兑换后记录兑换用户和时间，不能再次使用。

---

## 数据与日志

### 服务端

优先使用 `%PROGRAMDATA%\WinTunnelServer`，不可写时回退到 exe 同级的 `data\WinTunnelServer`，再回退到 `%LOCALAPPDATA%\WinTunnelServer`：

```text
wintunnel.db      用户、卡密、节点、节点端口分配、版本、审计
settings.json     端口/公网地址配置
updates\          客户端更新包
server.log        运行日志（2 MB 轮转，保留 4 份）
```

### 节点服务器

优先使用 `%LOCALAPPDATA%\WinTunnelNode`，不可写时回退到 exe 同级的 `data\WinTunnelNode`：

```text
settings.json   主服务端 API、节点 ID、节点令牌、控制端口、端口范围
node.log        节点日志
```

### 客户端

优先使用 `%LOCALAPPDATA%\WinTunnelClient`，不可写时回退到 exe 同级的 `data\WinTunnelClient`：

```text
settings.json   服务端地址、端口、用户名、隧道参数；勾选记住密码时含 DPAPI 密文
machine.json    机器码缓存（只含哈希，不含原始序列号）
client.log      客户端日志
updates\        下载的更新包
```

密码默认不保存；勾选“记住账号密码”后，只保存 Windows DPAPI 密文。会话令牌只保存在内存中。

### 安全

- 管理 API 是 **明文 HTTP**。密码不直接传输，但会话令牌、卡密、业务数据仍是明文。公网部署建议在 WireGuard / Tailscale / ZeroTier 加密网络中使用，或用 stunnel/反向代理加 TLS。
- 服务端控制台无登录、只在本机运行；没有开放远程管理 API，用户/卡密操作只能在服务端 GUI 中完成。
- 会话令牌 24 小时有效；服务端重启后内存会话清空，客户端需要重新登录。
- 登录失败有简单限流（同 IP 一分钟 10 次）。
- 用户到期后 API 仍允许登录以完成充值，但隧道认证会拒绝；客户端也会禁用连接按钮。
- 只暴露必要端口，不要把 RDP/数据库直接裸露在公网；尽量限制来源 IP。
- 卡密和数据库是授权凭据，请定期备份并限制服务端文件权限。

---

## 从源码运行

要求 Windows 10/11 + Python 3.10+（安装时包含 tcl/tk）。

```powershell
# 服务端
pythonw WinTunnelServer.pyw

# 客户端
pythonw WinTunnelClient.pyw

# 节点服务器
pythonw WinTunnelNode.pyw
```

运行测试：

```powershell
python -m unittest discover -s tests -p "test_*.py" -v
```

端到端验收（会真实启动 GUI、API、隧道、HTTP/回显服务）：

```powershell
python tests/server_app_e2e.py
python tests/client_app_e2e.py
```

生成 UI 截图：

```powershell
python tests/ui_shots.py
```

### 构建三个 EXE

```powershell
build_windows.bat
```

输出：

```text
dist\WinTunnelServer\WinTunnelServer.exe   主服务端便携目录版
dist\WinTunnelServer.exe                   主服务端单文件版
dist\WinTunnelNode\WinTunnelNode.exe       节点服务器便携目录版
dist\WinTunnelNode.exe                     节点服务器单文件版
dist\WinTunnelClient.exe                   客户端单文件版（推荐发布）
dist\WinTunnelClient\WinTunnelClient.exe   客户端便携目录版（开发调试用）
```

单文件客户端首次启动会解压到 `%TEMP%`，启动约慢 1～2 秒；临时目录被安全策略限制时，可以改用便携目录版。

---

## 会员下载

客户端安装包不再放在官网静态目录，也不能通过直接 URL 下载。

- 用户登录用户中心后，服务端检查授权是否有效。
- 有效会员通过 `GET /api/client/package` 下载单文件 `WinTunnelClient.exe`。
- 到期/禁用账号返回 403。
- 服务端优先读取 `WinTunnelServer.exe` 同级的 `client\WinTunnelClient*.exe`，同时兼容旧的 `.zip` 安装包。
- 便携服务端压缩包已经包含 `client\WinTunnelClient.exe`；单文件服务端需要把 `client` 文件夹放在 exe 同级。

## 官网用户中心

`site/` 内提供静态官网和用户中心：

- `login.html`：账号密码登录
- `register.html`：20 位卡密注册（网页注册不绑定机器）
- `recharge.html`：卡密充值
- `account.html`：授权、到期时间、机器绑定和端口

网页端使用新的受限 Web 会话：只能查看授权和充值，不能建立隧道，也不能重置机器码。网页登录/注册需要 HTTPS 和同源 `/api/` 反向代理；Nginx 示例见 [site/README.md](site/README.md)。

## 项目结构

```text
WinTunnelServer.pyw        主服务端入口
WinTunnelNode.pyw          节点服务器入口
WinTunnelClient.pyw        客户端入口
wintunnel/
  server_app.py            主服务端 GUI：用户/卡密/节点/版本、服务控制
  node_app.py              节点服务器 GUI：心跳、隧道承载
  client_app.py            客户端 GUI：登录、节点选择、充值、隧道
  china_map.py             中国地图轮廓与节点标记
  ticket.py                节点票据签发/校验
  geo.py                   客户端 IP 地理位置
  ui.py                    无边框未来感 UI 组件/背景/弹窗
  storage.py               SQLite：用户、卡密、节点、端口分配、审计
  auth.py                  挑战应答、会话、机器绑定
  ports.py                 主节点端口分配
  api.py                   主服务端 HTTP API
  client_api.py            客户端 API 封装
  machine.py               硬件指纹采集
  tray.py                  Windows 通知区托盘
  update.py                自动更新
  server.py                隧道节点核心
  client.py                隧道客户端核心
  protocol.py              二进制帧协议
  config.py                配置校验
  paths.py                 数据目录
  assets\china_outline.json 中国地图轮廓
site/                       静态官网：首页、下载、教程、FAQ
  index.html
  assets\styles.css
  downloads\                使用/部署文档（不含安装包）
tests/
  test_e2e.py              隧道核心测试
  test_platform.py         认证/API/卡密/更新测试
  node_e2e.py              主服务端 + 节点服务器分布式隧道验收
  server_app_e2e.py        服务端 GUI 集成验收
  client_app_e2e.py        客户端 GUI 登录+充值和隧道验收
  client_logout_e2e.py     退出登录后输入框焦点验收
```

---

## 常见问题

### 客户端“无法连接服务端”

1. 服务端是否点“启动服务”，状态是否为 `● ONLINE`。
2. TCP `7100` 是否放行（登录/充值走这个端口）。
3. 路由器/云安全组是否放行 `7100`。
4. 客户端 API 端口是否与服务端一致。

### 客户端日志提示“无法为流打开本地服务 / WinError 1225”

这不是主服务端或节点服务器错误，而是**公网端口已经收到访客连接，但客户端连接不到你填写的本地服务**。

- 本地网站没启动：先启动 IIS、Nginx、Python/Node 等服务。
- 本地端口填错：RDP 通常是 `3389`，网站通常是 `80` 或 `8080`。
- 隧道页点 **“检测本地服务”**，显示“可连接”后再建立隧道。
- 公网端口暴露后会收到扫描流量，日志出现几条 1225 是正常的；只要本地服务可用即可。
- 客户端建立隧道前会提示本地服务状态，但不再强制阻断；可以先建立隧道，再启动本地服务。

### 登录提示“机器码不一致”

账号已经绑定过另一台机器。管理员进入“用户管理”，选中用户，点“解绑机器”，然后客户端重新登录。

### 到期后无法连接

客户端“卡密充值”输入卡密，或让管理员在用户管理中兑换卡密。充值后重新点“建立隧道”。

### 客户端提示“登录状态已失效”

服务端重启会清空内存会话；重新登录即可。

### 版本检查一直失败

客户端只会在登录成功后检查更新；检查失败不会阻止登录。确认 API 端口可达、服务端已发布版本，并查看客户端日志。

### 杀毒软件误报

PyInstaller 单文件程序可能被误报。可改用便携目录版、从源码运行，或自行构建并签名。

---

## 已知限制

- 只支持 TCP，不支持 UDP。
- 管理 API 无 TLS；公网明文传输是当前版本最大的安全限制。
- 服务端重启后登录会话不持久化，客户端需重新登录。
- 机器绑定是严格模式：硬盘、主板、网卡、网关 MAC 任一变化都会导致机器码变化。
- 客户端自助解绑固定扣除 3 天；剩余不足 3 天时只能由管理员免费解绑。
- 端口范围耗尽时，新用户/续费用户登录会提示无可用端口，需要扩大范围或等待到期端口释放。
- 一个客户端实例维护一个隧道；需要多条隧道可运行多个客户端实例。
- 没有内置开机自启/Windows 服务。
- 没有流量统计、限速、多管理员权限模型。

---

## 合法使用

请只穿透你有权访问和管理的设备与服务。未经授权访问他人计算机、内网或数据可能违反法律。作者不对滥用行为承担责任。
