5.6 KiB
代码审查修改记录
修改概述
本次代码审查发现了若干问题并进行了修复,主要涉及安全性、并发安全和代码质量方面的改进。
1. 安全性修复
1.1 修复 FileExists 函数错误处理 (handler/file.go)
问题:FileExists 函数在文件不存在时错误地返回 os.IsExist(err),导致调用方无法正确区分"文件不存在"和其他错误。
修复:
// 修改前
if err != nil {
return nil, os.IsExist(err), err // 错误:os.IsExist 用于判断错误是否"已存在"
}
// 修改后
if err != nil {
if os.IsNotExist(err) {
return nil, false, nil // 正确返回"不存在"
}
return nil, false, err
}
1.2 增强文件处理器路径遍历防护 (handler/file.go)
问题:原有代码仅检查 ../ 前缀,无法防止符号链接导致的路径遍历攻击。
修复:添加了符号链接解析和真实路径验证逻辑:
// Resolve symlinks and clean path to prevent path traversal
realRoot, _ := filepath.EvalSymlinks(f.Root)
realPath, _ := filepath.EvalSymlinks(filepath.Dir(rPath))
if realPath != realRoot && !strings.HasPrefix(realPath, realRoot+string(filepath.Separator)) {
return nil, errors.New("not permitted")
}
2. 并发安全修复
2.1 修复 ProxyHandler.count 竞态条件 (handler/proxy.go)
问题:ProxyHandler.count 使用 int 类型,在高并发环境下存在数据竞态。
修复:使用 atomic.Int32 替代 int,确保计数器操作的原子性:
// 修改前
type ProxyHandler struct {
count int
}
// 修改后
type ProxyHandler struct {
count atomic.Int32
}
// 使用 Load()/Store() 方法进行原子操作
proxyIndex = p.count.Load()
p.count.Store(newCount)
3. 代码质量改进
3.1 使用 strings.EqualFold 替代 strings.ToLower 比较 (server/server.go)
问题:方法匹配时使用两次 strings.ToLower 调用效率较低。
修复:
// 修改前
if route.Method != "" && strings.ToLower(route.Method) != strings.ToLower(r.Method) {
// 修改后
if route.Method != "" && !strings.EqualFold(route.Method, r.Method) {
3.2 简化 IP 访问控制逻辑 (server/middleware.go)
问题:使用循环遍历切片检查元素存在性,代码冗余。
修复:使用 slices.Contains 和 strings.Cut 简化代码:
// 修改前
clientIP := strings.Split(r.RemoteAddr, ":")[0]
for _, ip := range deniedIPs {
if ip == clientIP { ... }
}
// 修改后
clientIP, _, _ := strings.Cut(r.RemoteAddr, ":")
if slices.Contains(deniedIPs, clientIP) { ... }
4. 待修复问题(已知但本次未修改)
4.1 MiddlewareLink.Clone() 方法存在反向迭代 Bug
问题:该方法从后向前迭代 list,但 Add 方法总是将元素插入到 Done 之前,导致克隆的中间件链顺序反转。
影响:如果中间件顺序重要,克隆后的中间件链可能无法正常工作。
4.2 测试 Test_RestMux_HandleFunc 失败
问题:该测试在修改前后均失败,属于已有问题。
原因:路由匹配逻辑与 RestMux.ServeHTTP 的路由匹配实现不一致。
5. 文件变更清单
| 文件 | 修改类型 |
|---|---|
| handler/file.go | 安全性修复 |
| handler/proxy.go | 并发安全修复 |
| server/server.go | 代码质量改进 |
| server/middleware.go | 代码质量改进 |
6. 新增功能:TCP代理服务器
6.1 功能概述
新增TCP代理服务器功能,支持在指定端口监听TCP请求并转发到指定服务器的指定端口。可以配置多个TCP代理。
6.2 新增文件
handler/tcpproxy.go - TCP代理处理器实现:
TcpProxyHandler结构体:管理TCP代理连接NewTcpProxyHandler函数:创建新的TCP代理处理器Start方法:启动TCP代理监听Stop方法:停止TCP代理服务器pipe方法:连接间数据转发
6.3 配置模型 (model/model.go)
新增 TcpProxyConfig 配置结构:
type TcpProxyConfig struct {
Name string `json:"name"` // 代理名称
Listen string `json:"listen"` // 监听地址,格式如 "0.0.0.0:8080"
Target string `json:"target"` // 目标服务器地址,格式如 "192.168.1.1:3306"
Enabled bool `json:"enabled"` // 是否启用
}
6.4 配置示例
在 config.json 中添加TCP代理配置:
{
"tcp_proxys": [
{
"name": "mysql-proxy",
"listen": "0.0.0.0:3307",
"target": "192.168.1.100:3306",
"enabled": true
},
{
"name": "redis-proxy",
"listen": "0.0.0.0:6380",
"target": "192.168.1.101:6379",
"enabled": true
}
]
}
6.5 从include目录加载TCP代理配置
TCP代理配置也可以从include目录中加载,使用 tcp_*.json 文件命名约定:
include目录结构:
./include/
├── servers/
│ ├── web.json
│ └── api.json
├── tcp_mysql.json # TCP代理配置
└── tcp_redis.json # TCP代理配置
include/tcp_mysql.json 示例:
{
"name": "mysql-proxy",
"listen": "0.0.0.0:3307",
"target": "192.168.1.100:3306",
"enabled": true
}
6.6 服务器管理 (server/manager.go)
新增TCP代理服务器管理功能:
TcpProxyManager:TCP代理处理器映射AddTcpProxy:注册TCP代理服务器StartTcpProxies:启动所有TCP代理服务器StopTcpProxies:停止所有TCP代理服务器
7. 构建验证
所有修改已通过 go build ./... 编译验证。