mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-23 03:31:53 +08:00
## 架构重构
- 全局变量消除,迁移至 Config/State 对象
- SMB 插件融合(smb/smb2/smbghost/smbinfo)
- 服务探测重构,实现 Nmap 风格 fallback 机制
- 输出系统重构,TXT 实时刷盘 + 双写机制
- i18n 框架升级至 go-i18n
## 性能优化
- 正则表达式预编译
- 内存优化 map[string]struct{}
- 并发指纹匹配
- SOCKS5 连接复用
- 滑动窗口调度 + 自适应线程池
## 新功能
- Web 管理界面
- 多格式 POC 适配(xray/afrog)
- 增强指纹库(3139条)
- Favicon hash 指纹识别
- 插件选择性编译(Build Tags)
- fscan-lab 靶场环境
- 默认端口扩展(62→133)
## 构建系统
- 添加 no_local tag 支持排除本地插件
- 多版本构建:fscan/fscan-nolocal/fscan-web
- CI 添加 snapshot 模式支持仅测试构建
## Bug 修复
- 修复 120+ 个问题,包括 RDP panic、批量扫描漏报、
JSON 输出格式、Redis 检测、Context 超时等
## 测试增强
- 单元测试覆盖率 74-100%
- 并发安全测试
- 集成测试(Web/端口/服务/SSH/ICMP)
247 lines
5.7 KiB
Go
247 lines
5.7 KiB
Go
package common
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
/*
|
|
state_test.go - State 并发安全测试
|
|
|
|
测试重点:
|
|
1. 并发安全性 - 多goroutine同时操作计数器
|
|
2. 原子操作一致性 - 增减计数正确
|
|
3. Reset功能 - 重置后计数器归零
|
|
|
|
不测试:
|
|
- 限速器(需要复杂的时间模拟)
|
|
- 简单getter/setter
|
|
*/
|
|
|
|
// TestState_ConcurrentPacketCount 测试并发包计数
|
|
func TestState_ConcurrentPacketCount(t *testing.T) {
|
|
s := NewState()
|
|
|
|
const goroutines = 100
|
|
const incrementsPerGoroutine = 1000
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(goroutines)
|
|
|
|
for i := 0; i < goroutines; i++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for j := 0; j < incrementsPerGoroutine; j++ {
|
|
s.IncrementPacketCount()
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
expected := int64(goroutines * incrementsPerGoroutine)
|
|
actual := s.GetPacketCount()
|
|
|
|
if actual != expected {
|
|
t.Errorf("并发计数不一致: 期望 %d, 实际 %d", expected, actual)
|
|
}
|
|
}
|
|
|
|
// TestState_ConcurrentTCPCount 测试并发TCP计数
|
|
func TestState_ConcurrentTCPCount(t *testing.T) {
|
|
s := NewState()
|
|
|
|
const goroutines = 50
|
|
const operationsPerGoroutine = 500
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(goroutines * 2) // 成功和失败各一半
|
|
|
|
// 成功连接
|
|
for i := 0; i < goroutines; i++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for j := 0; j < operationsPerGoroutine; j++ {
|
|
s.IncrementTCPSuccessPacketCount()
|
|
}
|
|
}()
|
|
}
|
|
|
|
// 失败连接
|
|
for i := 0; i < goroutines; i++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for j := 0; j < operationsPerGoroutine; j++ {
|
|
s.IncrementTCPFailedPacketCount()
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
expectedTotal := int64(goroutines * operationsPerGoroutine * 2)
|
|
expectedSuccess := int64(goroutines * operationsPerGoroutine)
|
|
expectedFailed := int64(goroutines * operationsPerGoroutine)
|
|
|
|
if s.GetPacketCount() != expectedTotal {
|
|
t.Errorf("总包计数不一致: 期望 %d, 实际 %d", expectedTotal, s.GetPacketCount())
|
|
}
|
|
if s.GetTCPPacketCount() != expectedTotal {
|
|
t.Errorf("TCP包计数不一致: 期望 %d, 实际 %d", expectedTotal, s.GetTCPPacketCount())
|
|
}
|
|
if s.GetTCPSuccessPacketCount() != expectedSuccess {
|
|
t.Errorf("TCP成功计数不一致: 期望 %d, 实际 %d", expectedSuccess, s.GetTCPSuccessPacketCount())
|
|
}
|
|
if s.GetTCPFailedPacketCount() != expectedFailed {
|
|
t.Errorf("TCP失败计数不一致: 期望 %d, 实际 %d", expectedFailed, s.GetTCPFailedPacketCount())
|
|
}
|
|
}
|
|
|
|
// TestState_Reset 测试重置功能
|
|
func TestState_Reset(t *testing.T) {
|
|
s := NewState()
|
|
|
|
// 增加一些计数
|
|
for i := 0; i < 100; i++ {
|
|
s.IncrementTCPSuccessPacketCount()
|
|
s.IncrementTCPFailedPacketCount()
|
|
s.IncrementUDPPacketCount()
|
|
s.IncrementHTTPPacketCount()
|
|
s.IncrementResourceExhaustedCount()
|
|
}
|
|
|
|
// 验证有值
|
|
if s.GetPacketCount() == 0 {
|
|
t.Fatal("重置前计数应该非零")
|
|
}
|
|
|
|
// 重置
|
|
s.ResetPacketCounters()
|
|
|
|
// 验证全部归零
|
|
if s.GetPacketCount() != 0 {
|
|
t.Errorf("重置后PacketCount应该为0, 实际 %d", s.GetPacketCount())
|
|
}
|
|
if s.GetTCPPacketCount() != 0 {
|
|
t.Errorf("重置后TCPPacketCount应该为0, 实际 %d", s.GetTCPPacketCount())
|
|
}
|
|
if s.GetTCPSuccessPacketCount() != 0 {
|
|
t.Errorf("重置后TCPSuccessPacketCount应该为0, 实际 %d", s.GetTCPSuccessPacketCount())
|
|
}
|
|
if s.GetTCPFailedPacketCount() != 0 {
|
|
t.Errorf("重置后TCPFailedPacketCount应该为0, 实际 %d", s.GetTCPFailedPacketCount())
|
|
}
|
|
if s.GetUDPPacketCount() != 0 {
|
|
t.Errorf("重置后UDPPacketCount应该为0, 实际 %d", s.GetUDPPacketCount())
|
|
}
|
|
if s.GetHTTPPacketCount() != 0 {
|
|
t.Errorf("重置后HTTPPacketCount应该为0, 实际 %d", s.GetHTTPPacketCount())
|
|
}
|
|
if s.GetResourceExhaustedCount() != 0 {
|
|
t.Errorf("重置后ResourceExhaustedCount应该为0, 实际 %d", s.GetResourceExhaustedCount())
|
|
}
|
|
}
|
|
|
|
// TestState_TaskCounters 测试任务计数器
|
|
func TestState_TaskCounters(t *testing.T) {
|
|
s := NewState()
|
|
|
|
// 初始值应该为0
|
|
if s.GetEnd() != 0 || s.GetNum() != 0 {
|
|
t.Error("初始任务计数器应该为0")
|
|
}
|
|
|
|
// 设置值
|
|
s.SetEnd(100)
|
|
s.SetNum(50)
|
|
|
|
if s.GetEnd() != 100 {
|
|
t.Errorf("End应该为100, 实际 %d", s.GetEnd())
|
|
}
|
|
if s.GetNum() != 50 {
|
|
t.Errorf("Num应该为50, 实际 %d", s.GetNum())
|
|
}
|
|
|
|
// 增加值
|
|
s.IncrementEnd()
|
|
s.IncrementNum()
|
|
|
|
if s.GetEnd() != 101 {
|
|
t.Errorf("IncrementEnd后应该为101, 实际 %d", s.GetEnd())
|
|
}
|
|
if s.GetNum() != 51 {
|
|
t.Errorf("IncrementNum后应该为51, 实际 %d", s.GetNum())
|
|
}
|
|
}
|
|
|
|
// TestState_ConcurrentTaskCounters 测试并发任务计数
|
|
func TestState_ConcurrentTaskCounters(t *testing.T) {
|
|
s := NewState()
|
|
|
|
const goroutines = 100
|
|
const incrementsPerGoroutine = 100
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(goroutines * 2)
|
|
|
|
// 并发增加End
|
|
for i := 0; i < goroutines; i++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for j := 0; j < incrementsPerGoroutine; j++ {
|
|
s.IncrementEnd()
|
|
}
|
|
}()
|
|
}
|
|
|
|
// 并发增加Num
|
|
for i := 0; i < goroutines; i++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for j := 0; j < incrementsPerGoroutine; j++ {
|
|
s.IncrementNum()
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
expected := int64(goroutines * incrementsPerGoroutine)
|
|
if s.GetEnd() != expected {
|
|
t.Errorf("End并发计数不一致: 期望 %d, 实际 %d", expected, s.GetEnd())
|
|
}
|
|
if s.GetNum() != expected {
|
|
t.Errorf("Num并发计数不一致: 期望 %d, 实际 %d", expected, s.GetNum())
|
|
}
|
|
}
|
|
|
|
// TestState_OutputMutex 测试输出互斥锁
|
|
func TestState_OutputMutex(t *testing.T) {
|
|
s := NewState()
|
|
|
|
counter := 0
|
|
const goroutines = 100
|
|
const incrementsPerGoroutine = 100
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(goroutines)
|
|
|
|
for i := 0; i < goroutines; i++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for j := 0; j < incrementsPerGoroutine; j++ {
|
|
s.LockOutput()
|
|
counter++
|
|
s.UnlockOutput()
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
expected := goroutines * incrementsPerGoroutine
|
|
if counter != expected {
|
|
t.Errorf("输出互斥锁保护失败: 期望 %d, 实际 %d", expected, counter)
|
|
}
|
|
}
|