Skip to content

Features

Juwan-Hwang edited this page Apr 11, 2026 · 30 revisions

功能特性

Zephyr 提供了一套完整的代理管理功能集,涵盖实时流量监控、智能节点选择、高级安全防护与跨平台适配。本文档对每一项核心功能进行详细的技术说明,并通过 Mermaid 图表直观展示数据流与处理逻辑。


目录


实时流量监控

Zephyr 内置了一套完全自研的实时流量可视化引擎,零第三方图表库依赖,基于原生 Canvas 2D API 从零构建双色面积图,提供流畅、低开销的实时网络流量展示。

数据流架构

流量数据从 Mihomo 内核出发,经过 HTTP Streaming 传输、逐行解析、滑动窗口缓冲,最终由 Canvas 2D 渲染引擎绘制为贝塞尔曲线面积图。以下时序图展示了完整的数据流转过程:

%%{init: {'themeVariables': {'fontSize': '10px', 'actorTextColor': '#ccc', 'signalColor': '#666', 'labelTextColor': '#999', 'labelBoxBkgColor': '#333', 'labelBoxBorderColor': '#555', 'lineColor': '#666', 'actorBkg': '#333', 'actorBorder': '#555', 'actorTextColor': '#ccc', 'signalTextColor': '#ccc', 'noteBkgColor': '#333', 'noteTextColor': '#ccc', 'noteBorderColor': '#555'}}}%%
sequenceDiagram
    participant MC as Mihomo Core
    participant HS as HTTP Stream<br/>(/traffic)
    participant WS as websocket.js<br/>(ReadableStream)
    participant SW as 滑动窗口<br/>(60 数据点)
    participant TC as traffic-chart.js<br/>(渲染引擎)
    participant CV as Canvas 2D<br/>(贝塞尔面积图)

    MC->>HS: GET /traffic (chunked JSON)
    activate HS

    loop 持续推送 (每秒约 1 次)
        HS-->>WS: {"up": 1024, "down": 51200}
        WS->>WS: TextDecoder 解码
        WS->>WS: 按换行符分割
        WS->>SW: JSON.parse(data)
        SW->>SW: pushToSlidingWindow()
        SW->>SW: 移除最旧数据点 (窗口 > 60)
        SW->>TC: 通知数据更新
        TC->>TC: requestAnimationFrame 调度
        TC->>CV: 清除画布
        TC->>CV: 绘制下载面积图 (紫色)
        TC->>CV: 绘制上传面积图 (蓝色)
        CV-->>TC: 渲染完成
    end

    Note over HS,WS: 连接断开时触发指数退避重连
    WS->>HS: 自动重连 (delay = min(1s * 2^attempt, 30s))
Loading

数据采集

流量数据通过 HTTP Streaming(非 WebSocket)从 Mihomo 内核的 /traffic 端点获取。与 WebSocket 方案相比,HTTP Streaming 具备更低的协议开销和更简洁的断线重连逻辑。

// 伪代码:HTTP Streaming 数据采集流程
const response = await fetch("http://127.0.0.1:9090/traffic");
const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  const text = decoder.decode(value, { stream: true });
  const lines = text.split("\n").filter(Boolean);

  for (const line of lines) {
    const data = JSON.parse(line);
    // data.up -> 上传速度 (bytes/s)
    // data.down -> 下载速度 (bytes/s)
    pushToSlidingWindow(data);
  }
}

可视化渲染

特性 说明
双通道面积图 紫色表示下载流量,蓝色表示上传流量,半透明填充叠加
贝塞尔曲线平滑 数据点之间使用贝塞尔曲线插值,避免折线的视觉生硬感
60 点滑动窗口 保留最近 60 个采样点,旧数据自动移出视口
requestAnimationFrame 节流 渲染频率与显示器刷新率同步,避免无效重绘
DPR 适配 Canvas 物理像素按 devicePixelRatio 缩放,高分屏下保持锐利
// 伪代码:DPR 适配与 Canvas 初始化
const canvas = document.getElementById("traffic-chart");
const ctx = canvas.getContext("2d");
const rect = canvas.getBoundingClientRect();
const dpr = window.devicePixelRatio || 1;

canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
ctx.scale(dpr, dpr);
// 后续绘制使用 CSS 像素坐标,Canvas 自动映射到物理像素

速度格式化

自动根据数值大小切换显示单位,保持界面简洁:

速度范围 显示格式 示例
< 1024 B/s XXX B/s 512 B/s
< 1024 KB/s X.XX KB/s 86.42 KB/s
>= 1024 KB/s X.XX MB/s 3.14 MB/s

以下决策树展示了速度值从原始字节到格式化显示的完整转换逻辑:

%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
    A[输入:速度值<br/>bytes/s] --> B{值 < 1024?}
    B -->|是| C[显示为 B/s<br/>格式:XXX B/s]
    B -->|否| D[值除以 1024<br/>转为 KB/s]
    D --> E{值 < 1024?}
    E -->|是| F[显示为 KB/s<br/>保留 2 位小数<br/>格式:X.XX KB/s]
    E -->|否| G[值再除以 1024<br/>转为 MB/s]
    G --> H[显示为 MB/s<br/>保留 2 位小数<br/>格式:X.XX MB/s]

    style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
    style B fill:#3B82F6,stroke:#2563EB,color:#fff
    style E fill:#3B82F6,stroke:#2563EB,color:#fff
    style C fill:#10B981,stroke:#059669,color:#fff
    style F fill:#10B981,stroke:#059669,color:#fff
    style H fill:#10B981,stroke:#059669,color:#fff
Loading

断线重连

采用指数退避重连策略,在连接中断时自动恢复,同时避免对内核造成请求风暴:

参数 说明
初始延迟 1 秒 首次重连等待时间
最大延迟 30 秒 退避上限
最大重试次数 15 次 超过后停止重连并提示用户
解析错误阈值 连续 10 次 触发强制重连(应对流格式异常)

退避公式:delay = min(initial * 2^attempt, max_delay)

以下流程图展示了 HTTP Streaming 连接建立、数据接收循环及断线重连的完整处理逻辑:

%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
    A[构造 Streaming URL<br/>http://127.0.0.1:9090/traffic] --> B[调用 fetch 发起请求]
    B --> C[获取 Response.body<br/>ReadableStream]
    C --> D[创建 TextDecoder]
    D --> E[进入数据读取循环]

    E --> F[reader.read 读取 chunk]
    F --> G{stream done?}
    G -->|是| H[触发指数退避重连<br/>delay = min 1s * 2^attempt, 30s]
    H --> I{重试次数 > 15?}
    I -->|是| J[停止重连<br/>提示用户连接中断]
    I -->|否| B

    G -->|否| K[TextDecoder 解码 chunk]
    K --> L[按换行符分割文本]
    L --> M[逐行 JSON.parse]
    M --> N{解析成功?}
    N -->|否| O[错误计数 +1]
    O --> P{连续错误 > 10?}
    P -->|是| Q[强制重连<br/>重置错误计数]
    Q --> B
    P -->|否| E

    N -->|是| R[pushToSlidingWindow]
    R --> S[移除最旧数据点<br/>窗口保持 60 个]
    S --> T[通知渲染引擎更新]
    T --> U[requestAnimationFrame 调度绘制]
    U --> E

    style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
    style B fill:#3B82F6,stroke:#2563EB,color:#fff
    style E fill:#3B82F6,stroke:#2563EB,color:#fff
    style H fill:#F59E0B,stroke:#D97706,color:#fff
    style Q fill:#EF4444,stroke:#DC2626,color:#fff
    style J fill:#EF4444,stroke:#DC2626,color:#fff
    style R fill:#10B981,stroke:#059669,color:#fff
    style T fill:#10B981,stroke:#059669,color:#fff
Loading

智能节点选择

Zephyr 提供了直观、高效的节点选择体验,结合响应式布局、延迟可视化与 3D 交互效果,让用户在海量节点中快速定位最优选择。

节点选择流程

从加载节点列表到最终切换代理,整个交互流程涉及前端 UI 渲染、Mihomo API 调用和界面状态同步。以下流程图展示了完整的节点选择链路:

%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
    A[加载节点列表] --> B[GET /proxies API]
    B --> C[解析代理组与节点数据]
    C --> D[渲染节点卡片网格]
    D --> E{用户操作}

    E -->|点击节点卡片| F[调用 switchProxy API]
    E -->|鼠标悬停 300ms| G[展开节点列表]
    E -->|滚轮滚动| H[切换当前选中节点]

    F --> I[PUT /proxies/group_name]
    I --> J[Mihomo 内核切换代理]
    J --> K[返回切换结果]
    K --> L[更新 UI 状态]
    L --> M[刷新延迟标签颜色编码]
    M --> N[同步托盘菜单状态]

    G --> O[显示完整节点列表]
    O --> P[展示延迟标签与节点名称]

    H --> Q[更新首页节点选择器显示]
    Q --> N

    style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
    style F fill:#3B82F6,stroke:#2563EB,color:#fff
    style J fill:#10B981,stroke:#059669,color:#fff
    style N fill:#F59E0B,stroke:#D97706,color:#fff
Loading

响应式网格布局

节点列表采用 1-4 列自适应网格,根据窗口宽度与屏幕分辨率动态调整列数:

窗口宽度 列数 适用场景
< 640px 1 列 窄窗口 / 小屏显示器
640px - 1024px 2 列 标准窗口
1024px - 1536px 3 列 大屏显示器
> 1536px 4 列 超宽屏 / 4K 显示器

延迟颜色编码

节点卡片上的延迟标签通过颜色直观反映连接质量:

延迟范围 颜色 含义
< 200ms 绿色 体验优良,适合实时应用
200ms - 500ms 黄色 可用,可能有轻微延迟
> 500ms 红色 延迟较高,不适合实时应用
测试中 灰色 + 加载动画 正在测量延迟
不可达 红色 + 超时标记 节点无法连接

排序模式

支持三种排序方式,通过节点面板顶部的排序按钮一键循环切换:

  1. 默认排序 -- 按 Mihomo 内核返回的原始顺序
  2. 按延迟排序 -- 延迟从低到高,不可达节点排末尾
  3. 按名称排序 -- 按节点名称的字典序排列

3D 悬浮效果

节点卡片在鼠标悬停时呈现 3D 透视旋转效果,通过 CSS perspective + rotateX/Y 实现,requestAnimationFrame 节流确保流畅:

/* 伪代码:3D 悬浮效果核心样式 */
.node-card {
  perspective: 800px;
  transform-style: preserve-3d;
  transition: transform 0.15s ease-out;
}
// 伪代码:鼠标跟踪 3D 旋转
card.addEventListener("mousemove", (e) => {
  requestAnimationFrame(() => {
    const rect = card.getBoundingClientRect();
    const x = (e.clientX - rect.left) / rect.width - 0.5;
    const y = (e.clientY - rect.top) / rect.height - 0.5;
    card.style.transform =
      `rotateY(${x * 15}deg) rotateX(${-y * 15}deg) scale(1.02)`;
  });
});

节点轮盘选择

以下时序图展示了节点轮盘(Roulette)选择的完整交互流程,从用户点击代理胶囊到最终同步托盘菜单的全链路:

%%{init: {'themeVariables': {'fontSize': '10px', 'actorTextColor': '#ccc', 'signalColor': '#666', 'labelTextColor': '#999', 'labelBoxBkgColor': '#333', 'labelBoxBorderColor': '#555', 'lineColor': '#666', 'actorBkg': '#333', 'actorBorder': '#555', 'actorTextColor': '#ccc', 'signalTextColor': '#ccc', 'noteBkgColor': '#333', 'noteTextColor': '#ccc', 'noteBorderColor': '#555'}}}%%
sequenceDiagram
    participant U as 用户
    participant UI as 前端 UI
    participant RO as 轮盘组件<br/>(Roulette)
    participant API as Mihomo API
    participant TM as 托盘菜单

    U->>UI: 点击代理胶囊
    activate UI
    UI->>RO: 渲染轮盘遮罩层
    activate RO
    RO->>API: GET /proxies/{group_name}
    activate API
    API-->>RO: 返回节点列表
    deactivate API
    RO->>RO: 渲染可滚动节点列表
    RO-->>U: 展示轮盘界面

    U->>RO: 点击目标节点
    activate RO
    RO->>UI: 调用 switchProxy(group, node)
    activate UI
    UI->>API: PUT /proxies/{group_name}
    activate API
    API->>API: Mihomo 切换代理节点
    API-->>UI: 返回切换结果
    deactivate API
    UI-->>RO: 切换成功
    deactivate UI

    RO->>RO: 更新当前激活节点显示
    RO->>RO: 关闭轮盘遮罩层
    RO-->>U: 显示切换成功反馈
    deactivate RO

    UI->>TM: 同步托盘菜单节点状态
    deactivate UI
Loading

渲染优化

  • content-visibility: auto:对可视区域外的节点卡片跳过渲染,大幅降低 DOM 计算开销
  • 滚动动画节流:所有滚动相关动画均通过 requestAnimationFrame 节流

订阅下载三重策略

Zephyr 提供功能完善的订阅管理系统,支持多种订阅格式、客户端伪装与灵活的下载策略。订阅下载采用三级回退策略,确保在各种网络环境下都能成功获取订阅。

下载流程

从 URL 验证到最终写入文件,订阅下载涵盖 SSRF 防护、多策略回退、内容解析、安全清理和加密存储等多个环节。以下流程图展示了完整的处理链路:

%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
    A[用户输入订阅 URL] --> B[SSRF 防护验证]
    B --> C{URL 合法?}
    C -->|否| ERR1[拒绝请求]

    C -->|是| D[第一优先级:直连下载]
    D --> E{下载成功?}
    E -->|是| K

    E -->|否| F[第二优先级:Mihomo 代理下载]
    F --> G{下载成功?}
    G -->|是| K

    G -->|否| H[第三优先级:系统代理下载]
    H --> I{下载成功?}
    I -->|是| K
    I -->|否| ERR2[返回下载失败错误]

    K[Base64 检测] --> L{内容为 Base64?}
    L -->|是| M[Base64 解码]
    L -->|否| N[直接使用原始内容]
    M --> O
    N --> O[YAML 解析]

    O --> P{解析成功?}
    P -->|否| ERR3[返回解析错误]
    P -->|是| Q[清除危险键]
    Q --> R[移除 script / script-path]
    Q --> S[移除 provider.path]

    R --> T[加密存储元数据]
    S --> T
    T --> U[get_machine_key 获取密钥]
    U --> V[obfuscate_string AES-256-GCM 加密 URL]
    V --> W[写入配置文件]
    W --> X[write_file_secure 设置 0o600 权限]
    X --> Y[返回配置信息]

    style B fill:#EF4444,stroke:#DC2626,color:#fff
    style D fill:#3B82F6,stroke:#2563EB,color:#fff
    style F fill:#8B5CF6,stroke:#7C3AED,color:#fff
    style H fill:#F59E0B,stroke:#D97706,color:#fff
    style Q fill:#EF4444,stroke:#DC2626,color:#fff
    style T fill:#10B981,stroke:#059669,color:#fff
    style ERR1 fill:#991B1B,color:#fff
    style ERR2 fill:#991B1B,color:#fff
    style ERR3 fill:#991B1B,color:#fff
Loading

多格式兼容

格式 处理方式 说明
Clash YAML 直接解析 标准 Mihomo / Clash 配置格式
Base64 编码 自动检测并解码 兼容 V2Ray / Shadowrocket 等分享链接格式

自动检测逻辑:当响应内容不包含 YAML 特征字符(-:#)时,尝试 Base64 解码。

客户端伪装

支持自定义 User-Agent 请求头,内置多个流行客户端的版本信息查询:

客户端 说明
Clash Verge 模拟 Clash Verge 客户端请求
Mihomo Party 模拟 Mihomo Party 客户端请求
FlClash 模拟 FlClash 客户端请求
自定义 用户可输入任意 UA 字符串

流量信息解析

自动解析订阅响应中的 subscription-userinfo 头部字段,展示流量使用进度:

subscription-userinfo: upload=1073741824; download=3221225472; total=107374182400; expire=1735689600
字段 说明
upload 已用上传流量(字节)
download 已用下载流量(字节)
total 总流量额度(字节)
expire 到期时间(Unix 时间戳)

其他功能

  • 批量更新:一键更新所有已添加的订阅
  • 拖拽导入:支持将 .yaml / .yml 文件直接拖拽到订阅页面导入

TUN 虚拟网卡

Zephyr 支持通过 TUN 虚拟网卡实现系统级透明代理,接管所有网络流量,无需手动配置系统代理。macOS 平台由于权限模型限制,需要通过 osascript 进行提权操作。

macOS TUN 提权流程

以下流程图展示了 macOS 平台上 TUN 模式从检查状态到最终激活的完整提权与启动过程:

%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
    A[用户请求启用 TUN] --> B[检查 TUN_TOGGLING 原子锁]
    B --> C{锁可用?}
    C -->|否| ERR1[返回:TUN 切换操作进行中]
    C -->|是| D[获取原子锁<br/>设置 10s 超时自动释放]

    D --> E[检查 TUN_MODE_ACTIVE 状态]
    E --> F{TUN 已激活?}
    F -->|是| G[执行关闭 TUN 流程]
    F -->|否| H[检查 CORE_STARTING 状态]

    H --> I{内核正在启动?}
    I -->|是| ERR2[返回:内核启动中]
    I -->|否| J[停止当前 Mihomo 进程]

    J --> K[构造 osascript 提权命令]
    K --> L[弹出系统授权对话框]
    L --> M{用户确认授权?}
    M -->|取消| N[释放原子锁]
    M -->|确认| O[以 root 权限启动 Mihomo]

    O --> P[轮询等待 root 进程启动]
    P --> Q{检测到 root 进程?}
    Q -->|否 - 超过 30s| R[返回:提权超时]
    Q -->|是| S[TCP 健康检查 API 端口]

    S --> T{端口可达?}
    T -->|否 - 重试 20 次| U[等待 500ms 后重试]
    U --> S
    T -->|是| V[设置 TUN_MODE_ACTIVE = true]
    V --> W[更新托盘图标为红色]
    W --> X[释放 TUN_TOGGLING 原子锁]
    X --> Y[TUN 模式激活完成]

    style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
    style K fill:#F59E0B,stroke:#D97706,color:#fff
    style O fill:#EF4444,stroke:#DC2626,color:#fff
    style V fill:#10B981,stroke:#059669,color:#fff
    style Y fill:#10B981,stroke:#059669,color:#fff
    style ERR1 fill:#991B1B,color:#fff
    style ERR2 fill:#991B1B,color:#fff
Loading

跨平台权限管理

平台 权限获取方式 说明
macOS osascript 提权 通过 AppleScript 弹出授权对话框,用户确认后以 root 身份启动
Windows 标准权限 直接调用系统 API 创建 TUN 接口
Linux 标准权限 通过 CAP_NET_ADMIN 或 root 权限创建 TUN 接口

并发安全

TUN 模式切换使用 AtomicBool 锁(TUN_TOGGLING)防止并发操作:

// 伪代码:TUN 切换并发控制
static TUN_TOGGLING: AtomicBool = AtomicBool::new(false);

async fn toggle_tun(enable: bool) -> Result<()> {
    if TUN_TOGGLING.compare_exchange(
        false, true,
        Ordering::Acquire,
        Ordering::Relaxed
    ).is_err() {
        return Err(Error::TunToggleInProgress);
    }

    let result = do_toggle_tun(enable).await;
    TUN_TOGGLING.store(false, Ordering::Release);
    result
}

托盘图标状态同步

系统托盘图标实时反映当前网络状态:

状态 图标颜色 说明
TUN 激活 红色 系统级透明代理已启用
系统代理 黄色 仅系统代理模式运行
直连 / 未启用 默认色 无代理或直连模式

安全设计

Zephyr 实现了一套多层纵深防御体系,覆盖网络请求安全、供应链安全、数据加密存储、文件系统防护等多个维度。其中 SSRF(服务端请求伪造)防护是网络请求安全的核心组件。

SSRF 防护链

针对 SSRF 攻击,Zephyr 实现了从 URL 解析到重定向跟踪的完整防护链。每次网络请求(包括重定向跳转)都经过严格的校验,最多跟踪 5 次重定向。以下流程图展示了完整的 SSRF 防护决策链:

%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
    A[解析目标 URL] --> B{协议为<br/>HTTP/HTTPS?}
    B -->|否| ERR1[拒绝:<br/>仅允许 HTTP 和 HTTPS]
    B -->|是| C[提取主机名]

    C --> D{主机名为<br/>私有地址?}
    D -->|是| ERR2[拒绝:<br/>localhost / .local / .test 等]
    D -->|否| E[DNS 预解析]

    E --> F{解析结果为<br/>私有 IP?}
    F -->|是| ERR3[拒绝:<br/>RFC 1918 / 环回 / 链路本地]
    F -->|否| G[DNS Pinning<br/>固定解析结果]

    G --> H[发起 HTTP 请求]
    H --> I{收到重定向?}
    I -->|否| J[返回响应内容]
    I -->|是| K{重定向次数<br/>< 5?}

    K -->|否| ERR4[拒绝:<br/>重定向次数超过上限]
    K -->|是| L[验证重定向目标 URL]

    L --> M{重定向协议<br/>合法?}
    M -->|否| ERR5[拒绝:<br/>非法重定向协议]
    M -->|是| N{重定向主机名<br/>为私有地址?}
    N -->|是| ERR6[拒绝:<br/>重定向到私有主机]
    N -->|否| O[DNS 预解析重定向目标]

    O --> P{重定向 IP<br/>为私有?}
    P -->|是| ERR7[拒绝:<br/>重定向到私有 IP]
    P -->|否| H

    style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
    style E fill:#F59E0B,stroke:#D97706,color:#fff
    style G fill:#3B82F6,stroke:#2563EB,color:#fff
    style H fill:#10B981,stroke:#059669,color:#fff
    style J fill:#10B981,stroke:#059669,color:#fff
    style ERR1 fill:#991B1B,color:#fff
    style ERR2 fill:#991B1B,color:#fff
    style ERR3 fill:#991B1B,color:#fff
    style ERR4 fill:#991B1B,color:#fff
    style ERR5 fill:#991B1B,color:#fff
    style ERR6 fill:#991B1B,color:#fff
    style ERR7 fill:#991B1B,color:#fff
Loading

防护层说明

防护层 机制 说明
DNS 解析验证 预解析 + IP 校验 在发起请求前先解析域名,验证目标 IP
私有 IP 拦截 CIDR 匹配 拦截指向 RFC 1918 / 环回 / 链路本地地址的请求
重定向链校验 最多 5 次跟踪 跟踪 HTTP 重定向链,每跳均执行 IP 校验
协议白名单 HTTP/HTTPS only 仅允许 httphttps 协议
DNS Pinning reqwest::resolve 固定 IP 防止 DNS Rebinding(TOCTOU)攻击

私有 IP 检测范围

IPv4 检测范围:

范围 CIDR 说明
私有地址 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 RFC 1918 私有网络
环回地址 127.0.0.0/8 本机回环
链路本地 169.254.0.0/16 自动分配地址
广播地址 255.255.255.255 网络广播
未指定 0.0.0.0 通配绑定地址

IPv6 检测范围:

范围 CIDR 说明
环回地址 ::1 本机回环
未指定 :: 通配绑定
唯一本地地址 fc00::/7 IPv6 私有网络(ULA)
链路本地 fe80::/10 IPv6 链路本地

供应链安全

订阅下载环节实施多层校验,防止恶意配置注入:

校验项 策略 说明
SHA256 校验 哈希比对 验证下载文件的完整性
可信域名白名单 域名匹配 仅允许从已知可信域名下载订阅
大小限制 100MB 超过限制的文件直接丢弃
路径遍历防护 5 轮 URL 解码 + 文件名净化 防止目录穿越攻击

数据加密存储

敏感数据(如订阅链接、认证信息)使用 AES-256-GCM 加密存储:

参数 说明
加密算法 AES-256-GCM 认证加密,同时保证机密性与完整性
密钥派生 PBKDF2-HMAC-SHA256 从用户密码派生加密密钥
迭代次数 100,000 次 有效抵御暴力破解
密钥绑定 机器标识 密钥与当前设备绑定,防止配置文件迁移泄露

文件权限控制

平台 权限设置 说明
Unix (macOS/Linux) 0600 仅文件所有者可读写
Windows DACL 通过 Windows 自由访问控制列表限制访问

命令限流

为防止命令被滥用或误操作,关键命令均设有频率限制:

命令 限流间隔 说明
start_core 3 秒 防止内核频繁启停
download_sub 5 秒 防止订阅下载过于频繁
exempt_uwp_apps 5 分钟 UWP 环回免除操作较重,需较长冷却

危险配置清除

加载外部配置时,自动清除以下危险字段,防止代码注入:

  • script / script-path -- 可能导致任意代码执行
  • provider 中的 path 字段 -- 可能导致路径遍历

配置热重载

Zephyr 的所有配置修改均支持热重载,无需重启 Mihomo 内核即可即时生效。配置更新通过 Tauri IPC 从前端传递到 Rust 后端,经过安全键保护、YAML 递归合并后写入文件,并通过 PATCH API 通知内核重新加载。

热重载流程

以下时序图展示了从用户在前端修改配置到最终生效的完整交互过程,涵盖 Tauri IPC 调用、安全键保护机制和 Mihomo API 通知:

%%{init: {'themeVariables': {'fontSize': '10px', 'actorTextColor': '#ccc', 'signalColor': '#666', 'labelTextColor': '#999', 'labelBoxBkgColor': '#333', 'labelBoxBorderColor': '#555', 'lineColor': '#666', 'actorBkg': '#333', 'actorBorder': '#555', 'actorTextColor': '#ccc', 'signalTextColor': '#ccc', 'noteBkgColor': '#333', 'noteTextColor': '#ccc', 'noteBorderColor': '#555'}}}%%
sequenceDiagram
    participant UI as 前端 UI
    participant IPC as Tauri IPC
    participant CM as config_manager<br/>(Rust 后端)
    participant FS as 文件系统
    participant API as Mihomo API<br/>(PATCH /configs)

    UI->>IPC: invoke("update_config", {patch})
    IPC->>CM: update_config(patch) 调用

    Note over CM: Step 1: JSON 转 YAML
    CM->>CM: serde_json::Value<br/>转为 serde_yaml::Value

    Note over CM: Step 2: 保存安全键
    CM->>CM: 备份 external-controller
    CM->>CM: 备份 secret

    Note over CM: Step 3: 递归合并
    CM->>CM: merge_yaml(existing, new, depth=0)
    Note over CM: 深度限制 50 层<br/>null 值表示删除键

    Note over CM: Step 4: 恢复安全键
    CM->>CM: 写回 external-controller
    CM->>CM: 写回 secret

    Note over CM: Step 5: 写入文件
    CM->>FS: 序列化为 YAML
    CM->>FS: 写入 run_config.yaml
    CM->>FS: 同步到订阅配置文件

    Note over CM: Step 6: PATCH 热重载
    CM->>API: PATCH /configs?force=true
    API-->>CM: 200 OK

    CM-->>IPC: Ok(())
    IPC-->>UI: resolve

    Note over UI: UI 刷新配置显示
Loading

递归合并算法

merge_yaml 函数实现了深度递归合并,支持嵌套结构的精确更新和键值删除:

// 伪代码:merge_yaml 递归合并实现
fn merge_yaml(base: &mut Value, overlay: &Value, depth: u32) {
    // 深度限制:防止栈溢出攻击
    if depth >= 50 {
        return;
    }

    if let (Value::Mapping(base_map), Value::Mapping(overlay_map)) = (base, overlay) {
        for (key, value) in overlay_map {
            if value.is_null() {
                // null 值表示删除该键
                base_map.remove(key);
            } else if let Some(existing) = base_map.get_mut(key) {
                // 递归合并嵌套结构
                merge_yaml(existing, value, depth + 1);
            } else {
                // 新增键值对
                base_map.insert(key.clone(), value.clone());
            }
        }
    } else {
        // 非映射类型:直接覆盖
        *base = overlay.clone();
    }
}

安全键保护机制

配置更新过程中,external-controllersecret 等安全关键字段会被临时备份并在合并后恢复,防止用户配置意外覆盖安全设置:

安全键 保护原因 恢复值
external-controller 防止 API 绑定到非 loopback 地址 127.0.0.1:{port}
secret 防止移除 API 认证 随机生成的 32 字节密钥

PATCH API 调用

PATCH /configs?force=true
Content-Type: application/json

{
  "dns": {
    "enable": true,
    "fake-ip": true,
    "nameserver": ["8.8.8.8", "1.1.1.1"]
  }
}

force=true 参数确保配置被强制重载,绕过内部缓存。


快速延迟测试

Zephyr 支持对代理节点进行快速延迟测试,帮助用户评估各节点的连接质量。

测试机制

通过 Mihomo RESTful API 对指定节点发起延迟探测:

GET /proxies/{proxy_name}/delay?url=http://www.gstatic.com/generate_204&timeout=5000
参数 说明
测试 URL http://www.gstatic.com/generate_204 Google 204 端点,轻量可靠
超时时间 5000ms 单次测试超时阈值
并发策略 并行请求 多节点同时测试,缩短总耗时

以下流程图展示了并发延迟测试的完整调度过程,从用户触发到结果展示的全链路:

%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
    A[用户触发延迟测试] --> B[UI 进入乐观加载状态]
    B --> C[显示加载动画<br/>所有节点标签置灰]

    C --> D[收集待测节点列表]
    D --> E[并行发起 API 调用]
    E --> F1[GET /proxies/node_1/delay]
    E --> F2[GET /proxies/node_2/delay]
    E --> F3[GET /proxies/node_N/delay]

    F1 --> G1[返回延迟结果]
    F2 --> G2[返回延迟结果]
    F3 --> G3[返回延迟结果]

    G1 --> H[异步汇总结果]
    G2 --> H
    G3 --> H

    H --> I[逐个更新延迟标签]
    I --> J[颜色编码刷新<br/>绿色 < 200ms / 黄色 < 500ms / 红色 > 500ms]
    J --> K{用户已启用排序?}
    K -->|是| L[按延迟重新排序节点]
    K -->|否| M[保持当前顺序]
    L --> N[测试完成]
    M --> N

    style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
    style B fill:#3B82F6,stroke:#2563EB,color:#fff
    style E fill:#3B82F6,stroke:#2563EB,color:#fff
    style H fill:#F59E0B,stroke:#D97706,color:#fff
    style J fill:#10B981,stroke:#059669,color:#fff
    style N fill:#10B981,stroke:#059669,color:#fff
Loading

乐观 UI

延迟测试采用乐观 UI 模式 -- 用户触发测试后,界面立即进入"测试中"状态并展示加载动画,无需等待首个结果返回。这种设计消除了请求延迟带来的感知等待时间。

结果展示

测试完成后,延迟数值实时更新至节点卡片,并同步触发颜色编码刷新(绿/黄/红)。


多种运行模式

Zephyr 提供三种代理运行模式,通过三段式滑块控件一键切换,适配不同的使用场景。

模式说明

模式 说明 适用场景
Rule(规则分流) 根据 Mihomo 配置中的规则集进行智能分流 日常使用,推荐模式
Global(全局代理) 所有流量均通过代理服务器转发 需要全部流量走代理的场景
Direct(直连) 所有流量直接发送,不经过代理 排查问题、访问本地服务

切换方式

通过 Mihomo RESTful API 实时切换:

PATCH /configs
Content-Type: application/json

{
  "mode": "rule"
}

UI 交互

三段式滑块控件带有平滑动画过渡效果,当前激活模式高亮显示。切换操作即时生效,无需重启内核。


跨平台支持

Zephyr 基于 Tauri v2 的跨平台能力,在 Windows、macOS 和 Linux 上提供一致的功能体验,同时针对各平台特性进行深度适配。

安装包格式

平台 格式 说明
Windows NSIS (.exe) + MSI (.msi) NSIS 为主推格式,MSI 适合企业部署
macOS DMG Apple Silicon + Intel 通用二进制(Universal Binary)
Linux DEB + AppImage + RPM 覆盖 Debian/Ubuntu、Fedora/RHEL 及通用发行版

Windows 特性

  • 系统代理设置:通过注册表原子写入配置系统代理,确保写入的原子性与一致性
  • UWP 环回免除:自动为 UWP 应用添加环回免除规则,使 UWP 应用也能走代理
    • 5 分钟限流防止频繁操作
    • 操作前弹出用户确认对话框

以下流程图展示了 UWP 环回豁免的完整操作流程,从用户触发到规则生效的全链路:

%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
    A[用户点击 UWP 环回豁免] --> B{限流检查<br/>距上次操作 > 5 分钟?}
    B -->|否| C[提示操作过于频繁<br/>请稍后再试]
    B -->|是| D[弹出确认对话框<br/>提示将执行 PowerShell 命令]

    D --> E{用户确认?}
    E -->|取消| F[操作取消]
    E -->|确认| G[执行 PowerShell<br/>CheckNetIsolation 命令]

    G --> H[枚举已安装的 UWP 应用列表]
    H --> I[展示 UWP 应用选择界面]
    I --> J[用户勾选目标应用]

    J --> K[逐个添加环回豁免规则<br/>CheckNetIsolation LoopbackExempt -a]
    K --> L{所有规则添加成功?}
    L -->|否| M[报告部分失败的应用]
    L -->|是| N[全部豁免规则添加成功]

    M --> O[刷新系统代理设置]
    N --> O
    O --> P[更新限流时间戳]
    P --> Q[操作完成<br/>UWP 应用可正常走代理]

    style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
    style B fill:#F59E0B,stroke:#D97706,color:#fff
    style G fill:#3B82F6,stroke:#2563EB,color:#fff
    style K fill:#3B82F6,stroke:#2563EB,color:#fff
    style Q fill:#10B981,stroke:#059669,color:#fff
    style C fill:#6B7280,stroke:#4B5563,color:#fff
    style F fill:#6B7280,stroke:#4B5563,color:#fff
Loading

macOS 特性

  • 通用二进制:单一代形同时支持 Apple Silicon (ARM64) 和 Intel (x86_64) 架构
  • TUN 提权:通过 osascript 调用 AppleScript 弹出系统授权对话框

Linux 特性

  • 桌面环境检测:自动识别当前桌面环境并调用对应的代理配置工具:
桌面环境 配置工具 命令示例
GNOME gsettings gsettings set org.gnome.system.proxy mode 'manual'
KDE Plasma kwriteconfig6 kwriteconfig6 --file kioslaverc --group "Proxy Settings" --key "ProxyType" 1
XFCE xfconf-query xfconf-query -c xfce4-proxy -p /mode -s manual
  • 窗口装饰:Linux 使用原生窗口装饰(有边框),Windows 和 macOS 使用无边框窗口

高级功能

自定义规则编辑器

Zephyr 内置了可视化的自定义规则编辑器,无需手动编辑 YAML 即可管理代理规则。

  • 13 种规则类型:DOMAIN、DOMAIN-SUFFIX、DOMAIN-KEYWORD、IP-CIDR、IP-CIDR6、GEOIP、GEOSITE、PROCESS-NAME、MATCH、SRC-IP-CIDR、SRC-PORT、DST-PORT、RULE-SET
  • Shadowrocket 规则导入:支持从 Shadowrocket 格式的规则列表一键导入
  • 可视化编辑:通过表单控件添加、编辑、删除、排序规则
  • 热重载:规则修改后通过 PATCH /configs?force=true 实时生效,无需重启内核

端口转发

支持创建 TCP/UDP 端口转发隧道,将本地端口流量转发到指定代理节点:

参数 说明
协议 TCP / UDP
监听地址 本地绑定的 IP 地址
监听端口 本地监听端口号
目标地址 转发目标的 IP 或域名
目标端口 转发目标的端口号
代理节点 使用的代理节点名称

DNS 覆写

提供独立的 DNS 配置面板,支持覆盖 Mihomo 内核的默认 DNS 设置:

  • Fake-IP 模式:启用后使用 Fake-IP 加速 DNS 解析
  • 自定义 DNS 服务器:可配置独立的 nameserver 列表
  • DNS 规则:支持按域名指定解析服务器

动态配置引擎

Zephyr 实现了一套递归渲染的动态配置引擎,用于管理 Mihomo 内核的复杂配置结构:

  • 递归渲染:根据配置的嵌套结构自动生成对应的编辑控件
  • 类型感知:根据值的类型(字符串、数字、布尔、数组、对象)自动选择合适的输入控件
  • 实时 PATCH:配置修改通过 HTTP PATCH 请求实时推送至内核
PATCH /configs?force=true
Content-Type: application/json

{
  "dns": {
    "enable": true,
    "fake-ip": true,
    "nameserver": ["8.8.8.8", "1.1.1.1"]
  }
}

开机自启

基于 Tauri autostart 插件实现开机自动启动,支持 Windows、macOS 和 Linux 三平台。

自动更新 (ensure_core_ready)

Zephyr 内置了完整的 Mihomo 内核自动更新机制,在应用启动时自动检查并更新内核版本。以下流程图展示了 ensure_core_ready 的完整更新链路:

%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
    A[应用启动] --> B[读取当前内核版本]
    B --> C[调用 get_latest_version API]
    C --> D{网络请求成功?}
    D -->|否| E[使用本地现有内核继续启动]
    D -->|是| F[获取最新版本号]

    F --> G{版本一致?}
    G -->|是| H[跳过更新<br/>直接启动内核]
    G -->|否| I[下载新版本二进制文件]

    I --> J{下载成功?}
    J -->|否| K[使用本地现有内核继续启动]
    J -->|是| L[计算 SHA256 校验值]

    L --> M{校验通过?}
    M -->|否| N[删除损坏文件<br/>使用本地现有内核继续启动]
    M -->|是| O[解压二进制文件]

    O --> P[停止当前 Mihomo 进程]
    P --> Q[替换旧版二进制文件]
    Q --> R{替换成功?}
    R -->|否| S[重试替换<br/>最多 3 次]
    S --> T{重试成功?}
    T -->|否| U[回退到旧版本启动]
    T -->|是| V
    R -->|是| V[启动新版 Mihomo 内核]

    V --> W{内核健康检查通过?}
    W -->|是| X[更新 UI 显示新版本号]
    W -->|否| U
    X --> Y[更新完成]

    style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
    style I fill:#3B82F6,stroke:#2563EB,color:#fff
    style L fill:#F59E0B,stroke:#D97706,color:#fff
    style P fill:#EF4444,stroke:#DC2626,color:#fff
    style V fill:#10B981,stroke:#059669,color:#fff
    style Y fill:#10B981,stroke:#059669,color:#fff
    style E fill:#6B7280,stroke:#4B5563,color:#fff
    style K fill:#6B7280,stroke:#4B5563,color:#fff
    style N fill:#6B7280,stroke:#4B5563,color:#fff
    style U fill:#6B7280,stroke:#4B5563,color:#fff
Loading

界面与体验

Zephyr 的前端界面完全基于原生 JavaScript 与 Tailwind CSS 构建,不依赖任何前端框架,实现了极致轻量与高度定制化的视觉体验。

玻璃拟态设计

全局采用 Glassmorphism(玻璃拟态)设计语言:

/* 玻璃拟态核心样式 */
.glass-panel {
  background: rgba(255, 255, 255, 0.08);  /* 半透明背景 */
  backdrop-filter: blur(16px);               /* 背景模糊 */
  -webkit-backdrop-filter: blur(16px);
  border-radius: 24px;                       /* 大圆角 */
  border: 1px solid rgba(255, 255, 255, 0.12);
}

主题系统

主题模式

模式 说明
深色模式 深色背景 + 浅色文字,适合夜间使用
浅色模式 浅色背景 + 深色文字,适合日间使用
Auto 跟随系统主题自动切换

主题色

提供 5 种预设主题色,同时支持通过取色器自定义任意颜色:

预设色 色值 视觉感受
薰衣草紫 #8B5CF6 优雅、科技感
海洋蓝 #3B82F6 沉稳、专业
翡翠绿 #10B981 自然、清新
玫瑰红 #F43F5E 活力、热情
琥珀橙 #F59E0B 温暖、活力

主题色通过 CSS 变量 --color-accent 全局生效,所有强调色元素(按钮、链接、选中态等)自动跟随切换。

iOS 风格 Toggle 开关

内置三种尺寸的 iOS 风格 Toggle 开关组件:

尺寸 适用场景
小 (SM) 列表项内嵌开关
中 (MD) 设置面板选项
大 (LG) 独立功能开关

应用不透明度调节

支持在 10% - 100% 范围内调节应用窗口不透明度,用户可根据个人偏好或桌面壁纸搭配调整透明度。

节点名称滚动动画

当节点名称过长超出容器宽度时,自动启用水平滚动动画:

/* 节点名称滚动动画 */
@keyframes text-scroll {
  0% { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}

.node-name-scrolling {
  animation: text-scroll 8s linear infinite;
  mask-image: linear-gradient(
    to right,
    transparent 0%,
    black 10%,
    black 90%,
    transparent 100%
  );
}

通过 mask-image 渐变遮罩实现文字两端的淡出效果,滚动动画自然流畅。

通知系统

内置轻量级通知系统,支持四种通知级别:

级别 用途 自动消失时间
info 一般信息提示 3 秒
success 操作成功反馈 3 秒
warning 警告信息 4 秒
error 错误信息 4 秒

自定义下拉菜单

所有下拉菜单组件通过 Portal 挂载到 document.body,避免被父容器的 overflow: hidden 裁切,确保在复杂布局中始终正确显示。

无边框窗口

平台 窗口样式 说明
Windows 无边框 自定义标题栏,完全掌控窗口外观
macOS 无边框 自定义标题栏,原生拖拽区域
Linux 原生窗口装饰 使用系统提供的窗口边框和标题栏,保证兼容性

返回 Home

Clone this wiki locally