feat: 后端限速实现 + 前端i18n全面国际化 + 安全与代码质量修复
后端: - trafficmgr: 实现 tc htb 限速(ApplyRateLimit/RemoveRateLimit),自动推导接口名 - 各协议服务: 代码质量改进与错误处理增强 前端: - protocols.js: 170个硬编码中文字符串全部转为 i18n key,中英文双语翻译 - 提取 fmtBytes() 到 utils/format.js 公共模块(消除 4 处重复) - router.js: 添加路由级权限守卫,非管理员无法直接 URL 访问管理页 - Tunnels.vue: SSE 日志流改用 fetch+ReadableStream,token 放 Authorization header - VPNUsers.vue: 修复 catch 块中文硬编码 fallback - 新增 TaskProgress 组件、taskmgr 后端任务管理
This commit is contained in:
1 parent
021d012478
commit
91974fc30f
26 files changed
+1977
-377
No files matched your search
@@ -4,7 +4,9 @@ package trafficmgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -106,25 +108,66 @@ func HandleExceed(tunnelID uint, action string, tunnelName string) {
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyRateLimit 使用 tc 设置隧道接口限速(需 root + tc 命令)
|
||||
// tunnelIface returns the network interface name for a tunnel, derived from
|
||||
// its protocol and ID. Returns "" if the protocol does not use a tc-able interface.
|
||||
func tunnelIface(tunnelID uint) string {
|
||||
var t model.Tunnel
|
||||
if store.DB == nil || store.DB.First(&t, tunnelID).Error != nil {
|
||||
return ""
|
||||
}
|
||||
switch t.Protocol {
|
||||
case "wireguard":
|
||||
return "wg" + strconv.FormatUint(uint64(t.ID), 36)
|
||||
case "openvpn":
|
||||
return "tun0"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyRateLimit 使用 tc htb 对隧道网络接口限速(需 root + tc 命令)
|
||||
func ApplyRateLimit(tunnelID uint, mbps int) {
|
||||
if mbps <= 0 {
|
||||
RemoveRateLimit(tunnelID)
|
||||
return
|
||||
}
|
||||
// tc 规则基于网络接口名,这里仅做记录;实际接口名需从隧道配置中获取
|
||||
// 完整实现需在 tunnel start 时获取 iface name 并传入
|
||||
if _, err := exec.LookPath("tc"); err != nil {
|
||||
tc, err := exec.LookPath("tc")
|
||||
if err != nil {
|
||||
return // tc 不存在则跳过
|
||||
}
|
||||
// 限速规则模板(需要接口名,此处占位)
|
||||
iface := tunnelIface(tunnelID)
|
||||
if iface == "" {
|
||||
return // 协议不支持 tc 限速
|
||||
}
|
||||
// 先清除旧规则再重建
|
||||
RemoveRateLimit(tunnelID)
|
||||
// tc qdisc add dev <iface> root htb default 10
|
||||
if out, err := exec.Command(tc, "qdisc", "add", "dev", iface, "root", "htb", "default", "10").CombinedOutput(); err != nil {
|
||||
log.Printf("[trafficmgr] tc qdisc add 失败 (iface=%s): %v: %s", iface, err, string(out))
|
||||
return
|
||||
}
|
||||
// tc class add dev <iface> parent root classid 1:10 htb rate <mbps>mbit
|
||||
if out, err := exec.Command(tc, "class", "add", "dev", iface, "parent", "root", "classid", "1:10", "htb", "rate", fmt.Sprintf("%dmbit", mbps)).CombinedOutput(); err != nil {
|
||||
log.Printf("[trafficmgr] tc class add 失败 (iface=%s): %v: %s", iface, err, string(out))
|
||||
return
|
||||
}
|
||||
log.Printf("[trafficmgr] 已对 %s 限速至 %d Mbps", iface, mbps)
|
||||
}
|
||||
|
||||
// RemoveRateLimit 清除限速规则
|
||||
// RemoveRateLimit 清除隧道接口上的 tc 限速规则
|
||||
func RemoveRateLimit(tunnelID uint) {
|
||||
if _, err := exec.LookPath("tc"); err != nil {
|
||||
tc, err := exec.LookPath("tc")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
iface := tunnelIface(tunnelID)
|
||||
if iface == "" {
|
||||
return
|
||||
}
|
||||
if out, err := exec.Command(tc, "qdisc", "del", "dev", iface, "root").CombinedOutput(); err != nil {
|
||||
// qdisc del 在无规则时返回非零,不算真正错误
|
||||
_ = out
|
||||
}
|
||||
}
|
||||
|
||||
// GetPolicy 获取隧道的流量策略(不存在则返回默认空策略)
|
||||
|
||||
Reference in new issue
Block a user