47 Commits
Author SHA1 Message Date
kevin 8398067acb feat: 连接列表显示客户端真实 IP,支持反代和 CDN 场景
新增可配置的 real_ip_headers(默认 CF-Connecting-IP > X-Real-IP >
X-Forwarded-For 降级取值),trusted_proxies 用于 gin 代理信任链。
WebSocket 连接建立时捕获真实 IP 并在 /profile 和 /admin 连接列表展示,
登录会话 IP 同步改用真实 IP。
2026-07-10 16:58:14 +08:00
kevin a98cdb0cac fix: 禁止管理员通过 UpdateUser 禁用自己的账号 2026-07-10 14:22:16 +08:00
kevin 9fda231d47 fix: 修复踢下线竞态窗口,先禁用再踢线防重连
KickUserClient 原先先踢线再禁用账号,客户端在两步之间自动重连时
status 仍为 1 可成功认证。调换顺序为先禁用+作废会话再踢线,确保
重连时认证已被拦截。
2026-07-10 14:21:59 +08:00
kevin 50e1661c1b feat: 实现每用户流量统计与定时落库
流量统计从全站按日聚合升级为 per-user 维度,并引入 60 秒定时
落库机制,服务崩溃最多丢失 60 秒数据。

后端:
- model/vpn.go: 新增 UserTrafficStat 模型(user_id + date 联合唯一索引)
- db/db.go: AutoMigrate 注册新模型
- vpn/tunnel.go: tunnelConn 增加 flushedRx/flushedTx 快照字段 +
  flushDelta() 增量计算;recordTraffic 改为 per-user 双写
  (user_traffic_stats + traffic_stats);连接断开 defer 改增量落库
- vpn/service.go: 新增 flushDone 字段 + trafficFlusher(60s 定时
  落库)+ flushAllTraffic;Stop() 先停 flusher 再最终 flush 全部
  在线连接增量;TotalLiveTraffic 改返回未落库增量避免与 DB 重复;
  新增 UserLiveTraffic(userID);ClientInfo 增加 RxBytes/TxBytes
- handler/traffic.go: 新建 5 个 handler(admin 3 个 + user 2 个)
- router.go: 注册 5 条新路由

新增 API:
- GET /api/admin/traffic/today  所有用户今日流量排行
- GET /api/admin/traffic/history?days=N  全站近 N 天流量历史
- GET /api/admin/traffic/users/:id?days=N  指定用户近 N 天流量
- GET /api/me/traffic/today  自己的今日流量
- GET /api/me/traffic?days=N  自己的近 N 天流量

前端:
- 安装 chart.js + vue-chartjs
- 新建 TrafficChart.vue 可复用柱状图组件(上行/下行双柱)
- AdminView.vue: 在线客户端表格增加 RX/TX 列 + 全站 7 天流量
  图表 + 用户今日流量排行表
- ProfileView.vue: 新增流量统计卡片(今日上行/下行/合计)+ 7 天
  流量柱状图
- zh.ts/en.ts: 新增 traffic 相关国际化
2026-07-10 14:18:06 +08:00
kevin aad8fa9848 feat: 用户个人页面展示当前 VPN 连接信息
- handler/vpn.go: 新增 GetMyVpnConnections,返回当前用户的在线
  VPN 连接列表(IP/连接时间)及 max_conns_per_user 上限
- router.go: 注册 GET /api/me/vpn/connections(普通用户可访问)
- ProfileView.vue: 新增"我的 VPN 连接"区块,含 n/max 徽章、
  IPv4/IPv6/连接时间表格,底部提示异常连接请修改密码
- zh.ts/en.ts: 新增 myVpnConnections/noConnections/
  abnormalConnectionHint 国际化
2026-07-10 13:53:49 +08:00
kevin c63440435e feat: 每用户最大连接数改为可配置,默认 30
将 maxConnsPerUser 从硬编码常量(3)改为数据库动态配置项,管理员可在
/admin/vpn 隧道设置中调整,保存后对新连接立即生效。

- model/vpn.go: VpnSetting 新增 MaxConnsPerUser 字段,gorm default:30
- db/db.go: 种子数据设默认 30;旧库回填 0 值为 30
- vpn/tunnel.go: 删除 maxConnsPerUser 常量,改读 VPN.Settings(),兜底 30
- handler/vpn.go: API 响应/请求结构体新增字段,校验范围 1-1000
- VpnView.vue: 隧道设置表单新增"每用户最大连接数"输入框
- zh.ts/en.ts: 新增 maxConnsPerUser 文案,更新首页多设备描述
- docs/client-development.md: 更新常量表为可配置项
2026-07-10 13:44:46 +08:00
kevin f6a1fb6288 fix: 踢下线同时禁用账号防重连,禁止管理员踢自己
- handler/vpn.go: KickUserClient 踢线后设置 status=0 并失效所有会话,
  阻止客户端自动重连;新增自检,目标为当前管理员时返回 400
- AdminView.vue: handleKick 调用 API 前自检,自己则提示去修改密码
- zh.ts/en.ts: 新增 cannotKickSelf,更新 confirmKick 提示含禁用账号
2026-07-10 13:33:04 +08:00
kevin f94aa3c4ac refactor: 在线客户端卡片移至管理后台首页,移除 body 退出按钮
- AdminView.vue: 新增 fetchVpnStatus/handleKick,用户信息卡片下方
  插入在线客户端表格(含踢下线按钮),30s 轮询同步刷新;
  删除 body 退出登录按钮及 handleLogout(header 已有退出入口)
- VpnView.vue: 移除在线客户端卡片及 handleKick(已迁移至 AdminView)
2026-07-10 13:25:55 +08:00
kevin a170a234b2 fix: 管理员修改用户信息后断开对应 VPN 连接
UpdateUser 在改密/改角色/禁用用户时,失效 Web 会话的同时调用
KickUser 断开 VPN 隧道,与 ChangePassword 行为对齐。
2026-07-10 13:17:45 +08:00
kevin b8720f413d fix: 自助修改密码后断开 VPN 连接并登出所有 Web 会话
- auth.go: ChangePassword 失效所有会话(不再排除当前会话),调用 KickUser 断开 VPN 隧道
- ProfileView.vue: 改密成功后 logout 清除 token,跳转登录页并携带 msg 参数
- LoginView.vue: 读取 query.msg 显示"密码已修改,请重新登录"绿色提示
- zh.ts/en.ts: 新增 login.passwordChanged 国际化 key
2026-07-10 13:11:46 +08:00
kevin fea3fc62f7 feat: 新增管理员踢下线 VPN 客户端功能
- vpn/service.go: ClientInfo 增加 user_id 字段,新增 KickUser 方法
  用读锁收集目标连接后逐个关闭 WebSocket,返回断开数量
- vpn/tunnel.go: info() 填充 UserID
- handler/vpn.go: 新增 KickUserClient handler,校验用户存在后调用 KickUser
- router.go: 注册 DELETE /api/admin/vpn/clients/:id
- VpnView.vue: 在线客户端表格新增操作列与踢下线按钮,handleKick 确认后调用 API 并刷新
- zh.ts/en.ts: 新增 kick/confirmKick/kickFailed 国际化 key
2026-07-10 13:01:26 +08:00
kevin 129c6c7a96 fix: 密码长度上限校验 + 请求体大小限制防 DoS
- 新增 validatePassword 校验函数(6-72 字节,bcrypt 硬上限),统一应用于 ChangePassword/CreateUser/UpdateUser,超长密码返回清晰提示而非迷惑性的"密码加密失败"
- 新增 BodyLimit 中间件(http.MaxBytesReader),对所有 /api JSON 端点限制 1 MiB 请求体,防止内存耗尽型 DoS;/ws 走连接劫持不受影响
2026-07-09 15:51:10 +08:00
kevin 195769534f docs: add MIT License 2026-07-09 14:53:12 +08:00
kevin eb5d79f81e 修改默认socket路径 2026-07-09 12:36:58 +08:00
kevin 098c601687 docs: update README for dynamic firewall config and UFW support
- Remove hardcoded VPN_SUBNET/VPN_SUBNET6 variables section
- Add firewall auto-management section explaining dynamic NAT/UFW config
- Update script flow to reflect removal of manual NAT config
- Fold manual NAT config into collapsible details (usually not needed)
- Add UFW to environment requirements and diag panel description
- Update troubleshooting table with UFW-related issues
- Update vpn/ directory description to include firewall management
2026-07-08 22:13:58 +08:00
kevin 4b82340a9f fix: dynamic firewall config + UFW support + anti-spoof bug fix
Root cause: UFW FORWARD policy DROP overrides lmvpn_nat accept rules.
DNS (small UDP) worked but TCP packets were silently dropped.

- Add firewall_linux.go: dynamic NAT/forward/UFW config from ApplySettings
- Add firewall_darwin.go/firewall_other.go: stubs
- Fix anti-spoof bug in switch.go: return dropPacket sentinel instead of
  nil, so spoofed packets are no longer written to TUN
- Simplify install_linux.sh: remove hardcoded subnets and NAT config
- Add UFW detection to diag panel
2026-07-08 20:11:15 +08:00
kevin 3306fc7ee4 修改前端内容 2026-07-08 12:23:50 +08:00
kevin cbe7aeca81 修改前端内容 2026-07-08 12:16:15 +08:00
kevin 170df5f457 fix: 刷新 /admin 被错误跳转到 /profile
路由守卫在 user 信息未加载时判断权限,刷新后 token 从 localStorage
恢复但 user 为 null,导致 adminOnly 守卫误判 role !== 'admin' 而跳转。
改为在已登录但 user 为 null 时先 await fetchUser() 加载用户信息再判断。
2026-07-08 12:00:07 +08:00
kevin f16683076f docs: README 添加客户端项目地址
https://github.com/wuwenfengmi1998/lmvpn_client
2026-07-07 20:23:45 +08:00
kevin d674d40ca8 docs: 重写 README,聚焦 Linux 部署流程
- 新增一键部署、手动部署、反向代理(Caddy/Nginx)、服务管理、升级等章节
- 整合配置说明、JWT 密钥、Unix Socket 权限、首次登录初始化
- 顶部标注服务端部署仅测试 Linux 正常
- 保留目录说明与安全提示
2026-07-07 20:19:46 +08:00
kevin c14fe5ec06 feat: 管理后台仪表盘统计卡片接入真实数据
新增 /api/admin/stats 聚合接口,填充运行时长、活跃设备、今日流量、在线节点四项卡片:
- VpnService 记录启动时间,提供 StartedAt/TotalLiveTraffic 方法
- 新增 TrafficStat 模型,客户端断开时 upsert 当日 rx/tx 流量(持久化)
- 前端 AdminView 调用 stats 接口并每 30 秒自动刷新
2026-07-07 15:43:29 +08:00
kevin 570dc82125 fix: install_linux.sh 强制覆盖本地修改,解决 pull 冲突
git pull 改为 git fetch + git reset --hard origin/main,
避免 npm install 修改 package-lock.json 后部署拉取失败
2026-07-07 15:11:06 +08:00
kevin 25c3ad685a feat: 前端多语言支持(中/英)与品牌 Logo 接入
多语言:
- 新增 vue-i18n,创建 src/locales/zh.ts、en.ts 语言包,按功能模块组织 key
- 新增 src/i18n.ts,语言检测优先级:localStorage > navigator.language(zh→中文,其他→英文)> 兜底英文
- 导航栏新增语言切换按钮(中/EN 一键切换),选择持久化到 localStorage
- 全部 View/Component 硬编码中文替换为 t() 调用,stores/auth.ts 错误消息同样国际化
- index.html lang 属性运行时动态更新

Logo:
- 替换 Vue 默认 logo 为 LmVPN 品牌 Logo(盾牌+网络节点)
- Header 导航栏:Logo 图标 + "LmVPN" 文字
- 首页标题区:大尺寸 Logo 展示
- Favicon 替换为 SVG 格式
2026-07-07 15:05:53 +08:00
kevin 5bce78cdb4 自动配置ipv6 2026-07-07 12:23:37 +08:00
kevin a770862c7c feat: 支持 IPv6 双栈地址派发
- model: VpnSetting 新增 Subnet6 字段,VpnReservation 新增 IPAddress6
- alloc: 处理 /64 等大子网 cidr.AddressCount 溢出,回退 65536 扫描上限
- protocol: initMessage 新增 ip6/prefix6/server_ip6(omitempty 向后兼容)
- service: 双分配器 alloc4+alloc6,ApplySettings 配置双 IP 与双路由,
  Allocate 返回 v4+v6 一对地址
- switch: SwitchConn 新增 AssignedIP6(),Register/Unregister 注册双 key,
  反欺骗按 IP 版本分别校验 v4/v6 源地址
- tunnel: tunnelConn 新增 assignedIP6,init 消息填充 v6 字段
- handler: 新增 validateSubnet6(/64~/126),settings/预留 API 全面支持 v6
- diag: 新增 IPv6 forwarding 与 NAT66 masquerade 检测
- install_linux.sh: 新增 VPN_SUBNET6、ipv6 forwarding、nft/ip6tables NAT66
- 前端: v6 子网输入框、v6 预留、v6 诊断卡片、客户端列表 v6 列
- 文档: init 消息、IP 分配、子网约束、TUN 配置、NAT、反欺骗全部更新
2026-07-07 11:38:21 +08:00
kevin 808b991483 fix: TUN 子网路由缺失导致客户端无下载流量
- service.go: 移除无意义的 peerIP = serverIP(对端指向自己),改为 nil
- service.go: Configure 之后新增 AddSubnetRoute 调用,确保内核有到 VPN 子网的路由
- tun_linux.go: Configure 增加 peerIP != nil 守卫,nil 时直接走无 peer 分支
- tun_darwin.go: 同上 peerIP != nil 守卫
2026-07-06 18:54:22 +08:00
kevin f2bb73a381 updoc 2026-07-06 15:13:40 +08:00
kevin 05e0a6de62 fix: NAT 检测与安装脚本优先使用 nft,解决 iptables-nft 不兼容问题
- diag_linux: checkMasquerade 改为优先 nft list ruleset,iptables 执行失败时 fall through 到 nft 而非直接返回
- diag_linux: 区分"iptables-nft 与原生 nft 表不兼容"与"权限不足"两种失败场景
- install_linux.sh: NAT 工具优先级反转为 nft 优先,iptables 回退,解决 Debian 12+ 上 iptables-nft 包装器操作原生 nft nat 表报 incompatible 的问题
- install_linux.sh: nft 分支增加 /etc/nftables.conf include 配置与 systemctl enable nftables,确保重启后规则自动加载
2026-07-06 14:59:40 +08:00
kevin 691ae99451 fix: NAT 检测与安装脚本适配无 iptables 的系统
- diag_linux: 用 findExecutable 在 /usr/sbin /sbin 等常见路径查找 iptables/nft,弥补 systemd 服务 PATH 不含这些目录
- diag_linux: iptables 不存在时回退 nft list ruleset 检测 masquerade,两者均无时返回明确安装提示
- diag_linux: 区分"未安装"与"权限不足",MASQUERADE 检测说明更精确
- install_linux.sh: NAT 段加 NAT_TOOL 选择,优先 iptables 回退 nft,无则提示安装而非 set -e 退出
- install_linux.sh: 新增 nftables 配置分支(lmvpn_nat 表,postrouting masquerade + forward accept),持久化到 /etc/nftables.d/lmvpn.nft
2026-07-06 14:53:30 +08:00
kevin 6ccfb57c80 feat: 默认子网改为 192.168.77.0/24,安装脚本授权 CAP_NET_ADMIN 与 iptables 配置
- 默认 VPN 子网由 192.168.3.0/24 改为 192.168.77.0/24(db seed、前端表单默认值与 placeholder 同步)
- install_linux.sh 顶部增加 VPN_SUBNET 可配置变量
- systemd unit 增加 AmbientCapabilities/CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW,服务以 lmvpn 用户运行即可创建 TUN,无需 root
- 脚本自动开启 net.ipv4.ip_forward 并持久化到 /etc/sysctl.d/99-lmvpn.conf
- 脚本自动检测出口网卡,幂等配置 iptables NAT MASQUERADE 与 FORWARD 放行规则
- 优先 netfilter-persistent 持久化,回退 iptables-save 写 /etc/iptables/rules.v4
2026-07-06 14:42:58 +08:00
kevin c8b170d532 feat: VPN 管理后台新增系统环境检测面板
- 新增 /api/admin/vpn/diag 端点,检测 TUN 创建能力、root、CAP_NET_ADMIN、ip_forward、MASQUERADE
- Linux 下解析 /proc/self/status CapEff 位判断 CAP_NET_ADMIN,读 /proc/sys/net/ipv4/ip_forward,执行 iptables 检查 MASQUERADE
- 非 Linux 平台显示"仅 Linux 适用"
- 前端 VpnView 新增系统环境检测卡片,每项以勾叉标识并附修复提示
2026-07-06 14:27:42 +08:00
kevin 44b51b3b04 feat: 实现第三层 TUN VPN 服务,支持后台 IP 分配
- 新增 TUN 设备层(water 库),分 linux/darwin 平台配置 IP/路由/MTU
- 实现 IP 分配管理:动态池自动分配 + 按用户静态预留,支持热更新
- 实现 PacketSwitch 共享 TUN 包转发:源 IP 防伪、按目的 IP 查表转发、allow-c2c
- 重写隧道:自研简化 WS 协议(文本帧 JSON 控制 init/ready,二进制帧=原始 IP 包)
- VpnService 单例管理 TUN 生命周期,子网变更踢线重建,预留增删热更新
- 新增 vpn_settings/vpn_reservations 表,AutoMigrate + 默认设置 seed
- 新增 Admin API:settings 读写、status、clients、reservations CRUD
- 前端新增 VpnView(/admin/vpn):状态面板/设置表单/在线客户端/静态预留
- main.go 启动时按 DB 设置初始化 VPN 服务
2026-07-03 14:49:56 +08:00
kevin 61189a53ec fix: 修复权限边界与安全问题
- JWT 密钥改为环境变量/配置文件/随机生成注入,移除硬编码
- AuthMiddleware 用数据库 role 覆盖 claims,降级/禁用即时生效
- 改 role/status 时主动失效目标用户会话
- /ws 支持 JWT 认证(?token=),兼容密码认证,CheckOrigin 改同源校验
- 默认管理员改用随机密码,stdout 与文件双交付
- 登录与 WS 密码认证加限流(5次/分钟)
- role 字段白名单校验(仅 admin/user)
- socket/目录权限可配置(sock_mode/sock_group/sock_dir_mode),默认兼容现状
- 配置文件权限收紧 0644→0600,目录 0755→0700
- 静态文件改用 http.Dir.Open + NoRoute,移除手动路径拼接
- 隧道加 SetReadLimit(1MB) 与单用户连接数上限(3)
- README 补充安全配置与生产部署说明
2026-07-03 14:12:03 +08:00
kevin c1d560fd4a feat: 会话管理 - 支持按设备粒度踢下线
- 新增 sessions 表,每次登录创建会话记录(记录 IP/UA)
- AuthMiddleware 改为基于 session 校验,可精确踢掉单个设备
- 自己改密码后踢掉其他设备,管理员改密码后踢掉该用户全部设备
- 新增 GET /api/me/sessions 查看活跃会话列表
- 新增 DELETE /api/me/sessions/:sessionId 踢掉指定会话
- 新增 DELETE /api/admin/users/:id/sessions 管理员强制下线某用户
- 兼容无 session_id 的旧 token,回退到 TokenInvalidBefore 校验
2026-07-03 10:52:39 +08:00
kevin f830406be7 up 2026-07-03 10:38:22 +08:00
kevin 03470475aa up install 2026-07-03 10:30:02 +08:00
kevin fe91a8ffb2 管理后台新增用户总数卡片,点击进入用户管理,移除header用户管理按钮 2026-07-03 10:24:52 +08:00
kevin e65b31abb0 新增用户管理和个人信息功能,支持CRUD操作和密码修改 2026-07-03 10:18:08 +08:00
kevin ca9b1e751c 写了个安装脚本 2026-07-02 22:51:26 +08:00
kevin 9bb35740fc 修改sock权限 2026-07-02 22:36:04 +08:00
kevin 6ca1c07cfa 封装路由 2026-07-02 22:34:15 +08:00
kevin 621625ad1e 重写前端 2026-07-02 21:03:51 +08:00
kevin 0634cadced 更新管理登录功能 2026-07-02 20:45:53 +08:00
kevin 91c9e12c3c 添加 WebSocket VPN 接口及用户认证
- 移动 config 包到 internal/config,新增 DatabaseConfig
- 使用 GORM + SQLite 管理用户数据,预留 MySQL 支持
- 新增 internal/model/user.go GORM 用户模型
- 新增 internal/db/db.go 数据库初始化及默认管理员
- 新增 internal/vpn/ WebSocket 鉴权与隧道骨架
- /ws 路径支持用户名+密码鉴权 (bcrypt)
- 心跳保活 + echo 隧道模式
2026-07-02 20:30:11 +08:00
kevin 5dddc93233 增加配置功能 2026-07-02 20:13:12 +08:00
kevin 083b6e5dbe init 2026-07-02 19:56:13 +08:00