kevin
|
6fd29fa5b2
|
fix: 全隧道模式跳过无意义的CIDR URL下载
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
全隧道模式下before-proxy、after-proxy和手动刷新三处仍会从URL
下载CIDR表,但下载结果永远不会被使用。添加ModeFull短路返回,
消除无意义的网络请求和连接延迟。
bump version to 0.6.9
v0.6.9
|
2026-07-10 15:01:36 +08:00 |
|
kevin
|
dc3e9beb14
|
chore: bump version to 0.6.8
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
v0.6.8
|
2026-07-09 23:22:22 +08:00 |
|
kevin
|
9d7d4c8287
|
fix: 设为纯托盘应用,启动不再在Dock显示图标
将Info.plist的LSUIElement改为true,应用以accessory模式启动,
永不显示Dock图标和系统菜单栏。移除运行时切换Dock可见性的
showDockIcon()/hideDockIcon()及其C实现setDockIconVisible,
这些调用在accessory模式下已无意义。activateApp()保留用于
窗口置于前台获取焦点。
|
2026-07-09 23:20:10 +08:00 |
|
kevin
|
469106d502
|
fix: 修复raceDial竞态条件导致daemon死锁无法连接
raceDial在首个连接成功后cancel剩余拨号goroutine时,dial goroutine
的select有两个同时就绪的case(缓冲channel可发送 vs raceCtx.Done()),
Go随机选择可能导致结果未发送,使drain循环永久阻塞,进而导致daemon
持有d.mu死锁,所有IPC命令(stats/stop/新start)全部阻塞。
DNS解析返回IPv4+IPv6双地址时触发此bug,约50%概率死锁。
修复:移除select,直接发送到缓冲channel(容量=len(ips)永不阻塞),
多余连接由drain循环负责关闭。
|
2026-07-09 23:19:46 +08:00 |
|
kevin
|
e61d4fedd8
|
fix: 修复钥匙串保存配置时errSecMissingEntitlement(-34018)错误
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
biometric钥匙串路径在缺少代码签名entitlement时自动降级到普通钥匙串;
添加LMVPN.entitlements文件和Makefile可选codesign步骤以支持未来Touch ID。
v0.6.7
|
2026-07-09 19:23:09 +08:00 |
|
kevin
|
1886d9b07b
|
up
|
2026-07-09 19:07:40 +08:00 |
|
kevin
|
b81b702433
|
feat: 添加IP竞速拨号器与IP偏好设置,连接状态显示域名与实际IP
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
- 新增竞速拨号器(racedial.go):域名连接时并行解析所有A/AAAA记录,
同时对所有IP发起TCP连接,第一个成功的胜出,确保选择延迟最低的地址
- ServerProfile新增IPPreference字段(auto/v4/v6),支持用户指定IP版本偏好
- 填写服务器IP时跳过域名解析直接使用IP,顺序failover
- 连接成功后状态栏显示「已连接 (域名 -> 实际IP)」
- DB迁移v6:server_profiles表添加ip_preference列
- WebSocket拨号与HTTP登录均使用竞速拨号器
- 补充中英文i18n翻译
v0.6.5
|
2026-07-09 18:46:55 +08:00 |
|
kevin
|
7febed50ac
|
docs: 添加 MIT 许可证
|
2026-07-09 14:53:04 +08:00 |
|
kevin
|
4caaacb68f
|
up
|
2026-07-09 11:29:25 +08:00 |
|
kevin
|
9b1cb668b1
|
尝试使用mac的指纹识别来授权,但是似乎没有效果
|
2026-07-09 11:27:40 +08:00 |
|
kevin
|
b52db70015
|
fix: 修复Windows/Linux编译缺失onAppActive符号的问题
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
onAppActive 仅在 dock_callback_darwin.go 中定义,导致非 darwin
平台 go vet/编译失败。在 dock_other.go 补充同名声明。
v0.6.2
|
2026-07-09 10:48:23 +08:00 |
|
kevin
|
1c4906c266
|
chore: bump version to 0.6.1
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
v0.6.1
|
2026-07-09 09:46:45 +08:00 |
|
kevin
|
ebe082500f
|
perf: 路由批量执行+CIDR聚合+并行脚本+连接步骤显示+CIDR刷新按钮
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
路由性能优化:
- 修复 macOS route 命令语法错误(去掉 -net 参数)
- 路由应用拆分为 Essential(ready前,4-6条命令<1s)+ Deferred(ready后,批量脚本)
- 新增 CIDR 聚合算法(cidrmerge.go),合并相邻 CIDR 块减少路由数量(10826->7500)
- 批量脚本执行:3平台各实现8个批量函数,临时脚本单次执行替代逐条进程创建
- 并行批量:拆为4个子shell并行执行,总时间降为1/4
连接步骤显示:
- stats 新增 connectStep + cidrError 原子变量
- 连接生命周期中设置步骤(fetch_cidrs/connecting/load_routes),UI 实时显示
- after-proxy CIDR 获取期间显示加载状态,获取失败显示错误提示
CIDR 刷新按钮:
- ipc 新增 CmdRefreshCIDR 命令
- daemon 处理刷新请求,session.RefreshCIDRs() 重新获取+添加路由
- UI 状态卡新增刷新按钮,proxy/bypass 模式已连接时显示
README:
- 补充 URL 获取时机注意事项(bypass模式after-proxy可能失败)
- 补充 CIDR 聚合与批量执行说明
v0.6.0
|
2026-07-09 09:44:49 +08:00 |
|
kevin
|
7c49ae4d72
|
up
|
2026-07-09 08:22:16 +08:00 |
|
kevin
|
7b4289ae00
|
feat: 路由模式重构(full/proxy/bypass) + CIDR动态URL获取 + 命中统计 + 连接稳定性修复
路由模式与CIDR配置重构:
- 路由模式从 full/split/custom 改为 full/proxy/bypass,移除 split 和 custom
- CIDR 按 IPv4/IPv6 分开配置,支持静态 CIDR + URL 动态获取
- URL 支持"代理前获取"(直连)和"代理后获取"(走隧道)两种时机
- 数据库迁移 v5 自动转换旧数据(custom_cidrs 拆分为 cidr_v4/v6,custom->proxy,split->full)
CIDR命中统计:
- 状态栏显示当前路由模式及 IPv4/IPv6 CIDR 命中数
- 代理模式: 显示命中/总数; 绕过模式: 显示已配置数 + 未命中目的地址数
- cidrTracker 在 pumpPackets 中逐包检查出站目的IP
连接稳定性修复(多轮):
- transport.Connect 添加 ctx 监听 goroutine,取消时关闭WS中断阻塞的ReadMessage
- auth.Login 加 context.Context 参数,可被 cancel 中断
- Disconnect() 先删路由再关TUN,避免断网窗口
- startSession 在 Connect 前释放 d.mu,避免锁持有过久
- onConnect 移除 SendStop 消除竞态
- before-proxy CIDR 获取移到 run 循环前,并行获取+5s超时,重连复用
- cidrTracker 加 RWMutex 防数据竞争
UI修复:
- CIDR URL 输入框改为水平滚动+纵向布局,防止撑宽窗口
- 路由模式为full时隐藏CIDR配置区域
|
2026-07-09 08:21:47 +08:00 |
|
kevin
|
15af9ef72c
|
fix: 移除showAndActivate避免误显示SystrayMonitor窗口
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
回退绕过GLFW遍历所有NSWindow的失败方案,恢复使用activateApp()+
showDockIcon()+window.Show()。保留真正生效的修复:正确selector
applicationShouldHandleReopen:hasVisibleWindows: + SetOnStarted延迟注册
v0.4.7
|
2026-07-09 00:49:53 +08:00 |
|
kevin
|
96b1a8839c
|
feat: 单实例锁与窗口恢复机制
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
- GUI 单实例锁: 新增 internal/instance 包,首实例监听专用端点,
第二实例发送 focus 信号后静默退出 (Unix: gui.sock, Win: 18924)
- 守护进程弱锁修复: NewServer() 在 os.Remove 前先 net.Dial 探测,
有活进程时拒绝启动,避免静默抢占 socket 导致孤儿进程
- macOS .app 重开恢复: 通过 class_addMethod 给 GLFWApplicationDelegate
注册 applicationShouldHandleReopen:hasVisibleWindows: 回调,
绕过 GLFW 直接用 Cocoa makeKeyAndOrderFront: 显示窗口
- 三平台覆盖: macOS/Linux 用 unix socket, Windows 用 TCP 端口
v0.4.6
|
2026-07-09 00:29:21 +08:00 |
|
kevin
|
c56fc0c21c
|
fix: CDN优选IP支持IPv6、格式校验及错误降级
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
- replaceHost() 自动为裸 IPv6 地址包裹方括号,修复 IPv6 URL 畸形问题
- 新增 ValidateServerIPs() 校验 IP 格式,保存配置时拦截非法输入
- GetServerIPList() 运行时自动过滤非法 IP 条目
- CDN IP 尝试时 TLS/认证错误降级为非致命,跳过该 IP 继续故障转移
而非终止整个连接循环(仅原始域名 ipIndex==0 时才判为致命)
- 占位符提示支持 IPv4/IPv6
v0.4.4
|
2026-07-08 23:09:26 +08:00 |
|
kevin
|
bb4e4552d8
|
feat: 记住上次选中的配置,下次启动自动选中
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
- 启用 AppConfig.DefaultProfileID 字段(此前声明但未使用)
- 启动时 loadProfiles() 优先选中上次记录的配置,找不到则回退到第一个
- 切换配置时立即持久化到 config.yml,防止崩溃丢失
- 使用 Profile ID 而非名称,避免重命名后失效
v0.4.3
|
2026-07-08 21:05:32 +08:00 |
|
kevin
|
3e7df0f4d8
|
fix: 修复连接状态下切换配置后断开重连导致异常的问题
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
问题现象:连接中切换配置 -> 断开 -> 连接,会出现连接后瞬间断开、
长时间无法重连。而先断开再切换配置则正常。
根因分析(三个层面的资源泄漏叠加):
1. pumpPackets 死锁 (session.go)
Disconnect() 只关闭 WebSocket transport,不关闭 TUN 设备。
TUN->WS goroutine 阻塞在 dev.Read(),pumpPackets 的 wg.Wait()
永远不返回,cleanup()(关闭 TUN/删路由)无法执行,导致
TUN 设备和路由泄漏。
2. 僵尸 eventLoop + 僵尸 IPC 连接 (view.go)
onDisconnect 不清空 ipcClient、不关闭 IPC 连接,旧 eventLoop
持续运行接收广播事件。eventLoop 正常事件处理无身份校验,
旧 session 的 disconnected 广播会覆盖新 session 的 connected 状态。
3. stopSession 不等待 goroutine 退出 (daemon.go)
d.session = nil 在 goroutine 仍在运行时即设置,新旧 session
并发执行导致 TUN/路由冲突。无 mutex 保护并发访问。
修复内容(10 项,3 个文件):
session.go:
- Disconnect() 新增 dev.Close() 解除 pumpPackets 死锁
- 新增 done channel,Disconnect() 阻塞等待 run goroutine 完全退出
- run() deferred setState 跳过用户主动断开时的冗余广播
- run() 顶部 ctx.Err() 检查后补 cleanup()
daemon.go:
- 新增 sync.Mutex 保护 session/cancel 并发访问
- 拆分 stopSession/stopSessionLocked 避免死锁
view.go:
- onDisconnect 置 ipcClient=nil + client.Close() 终止僵尸 eventLoop
- eventLoop 三个事件分支均加 if current == client 身份校验
- onConnect 覆盖前清理旧 IPC client
- setConnButtons 连接时禁用配置下拉框
v0.4.2
|
2026-07-08 20:57:50 +08:00 |
|
kevin
|
bf4744bb1d
|
feat: 添加服务端证书合法性验证(自定义CA/跳过验证/证书固定)
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
- 新增 internal/tlsconfig 包,集中构建 TLS 配置
- 修复 CDN 边缘 IP 故障转移时 HTTP 登录 TLS 验证失败的问题
- 支持自定义 CA 证书(内联 PEM + 文件路径,合并生效)
- 支持 InsecureSkipVerify 跳过证书验证
- 支持证书固定(SHA-256 指纹校验)
- TLS 验证错误设为不可恢复,避免无限重试
- Profile 编辑界面新增 TLS 设置区域,协议联动启用/禁用
- DB schema v4 迁移,新增 4 个 TLS 字段
v0.4.1
|
2026-07-08 11:33:36 +08:00 |
|
kevin
|
97cd9d4553
|
fix: 提交 Windows 图标资源(icon.ico/.syso)修复 CI
Release / build-macos (push) Canceled after 0s
Release / build-windows (push) Canceled after 0s
Release / release (push) Canceled after 0s
v0.3.9
|
2026-07-07 20:40:48 +08:00 |
|
kevin
|
56c802c385
|
fix: 禁用 MSYS 路径转换修复 ISCC /D 参数
|
2026-07-07 20:30:16 +08:00 |
|
kevin
|
6026beb107
|
fix: 修正 macOS ditto 打包选项为 --keepParent
|
2026-07-07 20:22:22 +08:00 |
|
kevin
|
8c903860c2
|
docs: README 添加服务端项目地址与 CI 说明
|
2026-07-07 20:13:50 +08:00 |
|
kevin
|
7abbf9e6cc
|
feat: 添加 GitHub Actions 多平台自动发布工作流
|
2026-07-07 20:12:09 +08:00 |
|
kevin
|
45b9fa24a1
|
up
|
2026-07-07 19:57:54 +08:00 |
|
kevin
|
4108adf1f7
|
up
|
2026-07-07 19:57:33 +08:00 |
|
kevin
|
6074dd5a73
|
up readme
|
2026-07-07 19:43:48 +08:00 |
|
kevin
|
3c076785f6
|
feat: Windows 安装器 + 修复 daemon 无法连接问题
- 新增 Inno Setup 安装器脚本 (installer/lmvpn.iss),支持自定义安装路径、
桌面快捷方式、安装前杀死旧进程,打包 wintun.dll
- Makefile 新增 installer-windows 目标,支持 ISCC 和 Wine 两种编译方式
- Windows IPC 从 AF_UNIX 改为 TCP (127.0.0.1:18923),解决提权 daemon 与
非提权 GUI 之间的完整性级别限制导致 daemon did not become reachable
- 修复 elevation_windows.go 中 ShellExecute 参数路径含空格时被截断的问题
(C:\Program Files\LMVPN\lmvpnd.exe → 只取到 C:\Program)
- ensureDaemon 重试次数 40→60,添加连接失败日志便于诊断
- 新增 IPCNetwork()/IPCAddress() 跨平台函数,统一 IPC 传输层抽象
|
2026-07-07 19:29:41 +08:00 |
|
kevin
|
019df7bc23
|
修复图标显示
|
2026-07-07 17:58:04 +08:00 |
|
kevin
|
9a1aca5d1b
|
up
|
2026-07-07 17:48:48 +08:00 |
|
kevin
|
027d837cb2
|
fix: 修复 Windows 端密码无法持久化的问题
Windows 端使用内存版 MemStore(keychain_other.go, 构建标签 !darwin),
进程退出后密码丢失,导致每次启动都需重新输入密码才能连接。
新增 keychain_windows.go,基于 Windows 凭据管理器(Credential Manager)
实现 Store 接口,密码经 Windows 登录凭据加密并持久化,跨重启保留。
keychain_other.go 构建标签收窄为 !darwin && !windows,作为 Linux 回退。
macOS 版本不受影响(仍由 keychain_darwin.go 独占编译)。
|
2026-07-07 17:47:41 +08:00 |
|
kevin
|
0c5e996bfd
|
fix: 修复 Windows 端 IPv6 无法下行的问题
根因: netsh interface ipv6 命令参数名用错
- configureIPv6Addr: name= → interface=,IPv6 地址未实际分配到适配器
- SetMTU IPv6: name= → interface=
路由修复:
- cidrToV6Prefix: 用 Mask.Size() 取前缀长度,修复 fmt.Sprintf(%d, mask) 输出字节切片的 bug
- addRoute6/deleteRoute6: netsh → route -6,用 :: 作 on-link gateway
- addRouteVia6/deleteRouteVia6: 加 -6 flag
- defaultGateway6: route -6 print :: → route -6 print(避免过滤掉 ::/0)
- applyFull: IPv6 bypass 路由失败不再阻断全隧道路由
|
2026-07-07 17:37:09 +08:00 |
|
kevin
|
65a5932eba
|
feat: 支持 Windows x86_64 平台编译
- 新增 WinTun TUN 设备实现(tun_windows.go),无需安装驱动,
wintun.dll 嵌入 exe 运行时自动释放
- 新增 Windows 路由管理(route_windows.go),使用 route/netsh 命令
- 新增 Windows 路径(paths_windows.go),使用 %APPDATA%/%LOCALAPPDATA%
- 拆分 daemon 启动逻辑:launch_unix.go(Setsid) / launch_windows.go
(CREATE_NEW_PROCESS_GROUP),公共代码提取到 launch_common.go
- 拆分提权逻辑:elevation_darwin.go(osascript) / elevation_windows.go
(ShellExecute UAC) / elevation_other.go(pkexec)
- IPCSocketPath 按平台分散,Windows 用 %TEMP%\lmvpn.sock
- daemon 二进制名用编译时常量(daemonBinaryName),按平台选定 .exe 后缀
- Makefile 新增 build-windows 目标
- 重新标记 !darwin 文件为 !darwin && !windows
|
2026-07-07 16:50:42 +08:00 |
|
kevin
|
6b9960076d
|
up
|
2026-07-07 14:40:07 +08:00 |
|
kevin
|
56102589f6
|
feat: 认证失败时停止重连并提示用户
密码错误、账户禁用、令牌过期或限流等永久性认证错误不再无限
重连,改为置 StateError 并通过 EvError 弹窗告知用户具体原因
(中英文本地化)。网络错误仍正常指数退避重试。
- protocol: 新增 AuthErrorCode 类型与消息映射
- transport: AuthError/ServerError 携带 Code 字段
- vpn: run() 循环识别致命认证错误并停止,新增 onError 回调
- ipc/daemon/ui: 打通错误码到 UI 的本地化展示
|
2026-07-07 14:37:26 +08:00 |
|
kevin
|
6daa73fdb0
|
增加图标
|
2026-07-07 14:16:09 +08:00 |
|
kevin
|
abcbb6ae68
|
更新项目连接
|
2026-07-07 13:44:37 +08:00 |
|
kevin
|
9c16d804d9
|
修复按钮逻辑bug
|
2026-07-07 13:34:48 +08:00 |
|
kevin
|
e08480f609
|
整合配置列表
|
2026-07-07 13:16:07 +08:00 |
|
kevin
|
4420532a66
|
fix: ensureDaemon 自动检测并重启过期守护进程
问题: 重新构建后 IPv6 等新功能不生效,客户端仍运行旧代码。
根因: ensureDaemon() 通过 IPC socket 拨号时,若旧 daemon 进程仍在
运行(重建后未退出),GUI 会直接复用旧进程,永不启动新二进制。
日志证实旧 daemon 处理连接(init 日志无 ip6 字段),新代码从未执行。
解决方案: 新增版本握手协议,GUI 启动时查询 daemon 构建版本,
版本不匹配则自动关闭旧进程并启动新的。
- 新建 internal/version 包,GUI 与 daemon 共享同一 Version 变量,
均通过 Makefile ldflags 注入
- IPC 新增 CmdVersion 命令,daemon 返回 version.Version;
Response 增加 Version 字段,Client 新增 QueryVersion() 方法
- ensureDaemon() 拨号后查询版本,不匹配则发 CmdShutdown、等待
socket 释放、重新启动 daemon;旧 daemon 不识别 CmdVersion 时
返回错误,同样触发重启
- Makefile LDFLAGS 改为注入 lmvpn/internal/version.Version
|
2026-07-07 12:42:23 +08:00 |
|
kevin
|
a332857973
|
up
|
2026-07-07 12:24:48 +08:00 |
|
kevin
|
8f6daf9f49
|
feat: 新增 IPv6 双栈支持
- 协议: InitMessage 增加 ip6/prefix6/server_ip6 字段(omitempty,向后兼容)
- TUN: Device 接口新增 ConfigureIPv6, macOS 用 ifconfig inet6, Linux 用 ip -6 addr add
- 路由: full 模式自动添加 ::/1+8000::/1, v6 服务器旁路 /128, resolveHosts 双栈解析
- 会话: setupTUN 解析 v6 字段并配置 TUN+路由, connectOnce 传 v6 给 stats/日志
- 统计: SetConnected(ip,ip6), Snapshot.AssignedIP6
- DB: connection_logs 增加 assigned_ip6 列 + migrateV3 幂等迁移
- UI: 状态卡片新增独立 IPv6 行, 始终可见(未获取显示 IPv6: —)
- 文档: 同步 client-development.md 至服务端 IPv6 版本
|
2026-07-07 12:24:20 +08:00 |
|
kevin
|
e867c8e248
|
修复滚动问题
|
2026-07-06 21:17:00 +08:00 |
|
kevin
|
43adeb9684
|
功能基本实现
|
2026-07-06 21:08:30 +08:00 |
|
kevin
|
5134290bf2
|
增加版本显示
|
2026-07-06 21:04:25 +08:00 |
|
kevin
|
96278fdf37
|
拆分服务器地址配置为独立字段,支持CDN优选IP故障切换,新增重置数据库按钮
- model: ServerURL → Protocol/Host/ServerIPs/Port/Path 五个字段
- db: 自动迁移旧 server_url 列到新表结构
- ui: 配置窗口改为横向分组布局,保存失败时不再关闭窗口
- transport: 支持 TLS SNI + Host 头覆盖以连接 CDN 边缘节点
- session: CDN IP 列表连接失败自动切换到下一个
- 新增重置数据库按钮,一键清空所有配置
|
2026-07-06 20:58:11 +08:00 |
|
kevin
|
32471e25b0
|
修复滚动问题
|
2026-07-06 20:29:10 +08:00 |
|
kevin
|
12210423f2
|
修改logo,修改配置页面的窗口
|
2026-07-06 20:22:25 +08:00 |
|