Files
fscan/core/service_probe_strategy_test.go
T
ZacharyZcR 71b92d4408 feat: v2.1.0 核心重构与功能增强
## 架构重构
- 全局变量消除,迁移至 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)
2026-01-11 20:16:23 +08:00

247 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package core
/*
service_probe_strategy_test.go - SmartProbeStrategy 策略逻辑测试
测试重点:
1. 新探测策略 - 使用 Probe.Ports 和 Rarity 排序
2. 动态超时 - 使用 TotalWaitMS
3. NULL 回退 - 隐式 NULL 探测器匹配
说明:
- 只测试策略逻辑,不测试实际的网络IO(那是集成测试的职责)
*/
import (
"testing"
"time"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/core/portfinger"
)
// =============================================================================
// 测试1:新探测策略(使用 Probe.Ports
// =============================================================================
// TestNewStrategy_ProbePortsUsed 验证新策略使用 Probe.Ports 字段
func TestNewStrategy_ProbePortsUsed(t *testing.T) {
v := portfinger.GetGlobalVScan()
// 验证端口80有对应的探测器
probes := v.GetProbesForPort(80)
if len(probes) == 0 {
t.Error("端口 80 应该有探测器")
}
// 验证 GetRequest 探测器在列表中
found := false
for _, p := range probes {
if p.Name == "GetRequest" {
found = true
t.Logf("✓ GetRequest 探测器存在于端口 80 的探测器列表中 (rarity=%d)", p.Rarity)
break
}
}
if !found {
t.Error("GetRequest 探测器应该在端口 80 的列表中")
}
}
// TestNewStrategy_RaritySorting 验证探测器按 Rarity 排序
func TestNewStrategy_RaritySorting(t *testing.T) {
v := portfinger.GetGlobalVScan()
probes := v.GetProbesForPort(80)
if len(probes) < 2 {
t.Skip("端口 80 的探测器数量不足,跳过排序测试")
}
// 验证按 rarity 从低到高排序
for i := 1; i < len(probes); i++ {
prev := probes[i-1].Rarity
curr := probes[i].Rarity
// 0 视为 10
if prev == 0 {
prev = 10
}
if curr == 0 {
curr = 10
}
if prev > curr {
t.Errorf("探测器未按 rarity 排序: [%d]=%d > [%d]=%d",
i-1, probes[i-1].Rarity, i, probes[i].Rarity)
}
}
t.Logf("✓ 端口 80 的 %d 个探测器已按 rarity 排序", len(probes))
}
// =============================================================================
// 测试2SSL 端口探测
// =============================================================================
// TestSSLProbes_Port443 验证 443 端口的 SSL 探测器
func TestSSLProbes_Port443(t *testing.T) {
v := portfinger.GetGlobalVScan()
// 获取 ports 包含 443 的探测器
probes := v.GetProbesForPort(443)
t.Logf("端口 443 的 ports 探测器: %d 个", len(probes))
// 获取 sslports 包含 443 的探测器
sslProbes := v.GetSSLProbesForPort(443)
t.Logf("端口 443 的 sslports 探测器: %d 个", len(sslProbes))
// 至少应该有一些 SSL 相关探测器
if len(probes) == 0 && len(sslProbes) == 0 {
t.Error("端口 443 应该有探测器")
}
// 验证 TLSSessionReq 存在
for _, p := range probes {
if p.Name == "TLSSessionReq" {
t.Logf("✓ TLSSessionReq 存在于 ports 列表")
return
}
}
for _, p := range sslProbes {
if p.Name == "TLSSessionReq" {
t.Logf("✓ TLSSessionReq 存在于 sslports 列表")
return
}
}
}
// =============================================================================
// 测试3Intensity 过滤
// =============================================================================
// TestIntensityFilter 验证 intensity 过滤功能
func TestIntensityFilter(t *testing.T) {
// 创建测试探测器
probes := []*portfinger.Probe{
{Name: "p1", Rarity: 1},
{Name: "p2", Rarity: 5},
{Name: "p3", Rarity: 9},
}
// intensity=5 应该过滤掉 rarity=9 的探测器
filtered := portfinger.FilterProbesByIntensity(probes, 5)
if len(filtered) != 2 {
t.Errorf("intensity=5 应该返回 2 个探测器,实际返回 %d", len(filtered))
}
// 验证 rarity=9 的探测器被过滤
for _, p := range filtered {
if p.Rarity > 5 {
t.Errorf("rarity=%d 的探测器不应该通过 intensity=5 的过滤", p.Rarity)
}
}
t.Log("✓ Intensity 过滤功能正常")
}
// =============================================================================
// 测试4:Scanner 创建和基本功能
// =============================================================================
// TestSmartPortInfoScanner_Creation 验证 Scanner 可以正常创建
func TestSmartPortInfoScanner_Creation(t *testing.T) {
config := common.GetGlobalConfig()
if config == nil {
config = &common.Config{}
config.PortMap = make(map[int][]string)
}
// 使用 nil 连接(实际测试中会使用真实连接)
scanner := NewSmartPortInfoScanner("127.0.0.1", 80, nil, 3*time.Second, config)
if scanner == nil {
t.Fatal("Scanner 创建失败")
}
if scanner.Port != 80 {
t.Errorf("端口设置错误: 期望 80, 实际 %d", scanner.Port)
}
t.Log("✓ Scanner 创建成功")
}
// =============================================================================
// 测试5:动态超时常量
// =============================================================================
// TestDefaultConstants 验证默认常量值
func TestDefaultConstants(t *testing.T) {
// 验证默认等待时间
if defaultTotalWaitMS != 6000 {
t.Errorf("defaultTotalWaitMS 应该是 6000,实际是 %d", defaultTotalWaitMS)
}
// 验证默认 intensity
if defaultIntensity != 7 {
t.Errorf("defaultIntensity 应该是 7,实际是 %d", defaultIntensity)
}
t.Logf("✓ 默认常量: TotalWaitMS=%d, Intensity=%d", defaultTotalWaitMS, defaultIntensity)
}
// =============================================================================
// 测试6:端口范围解析
// =============================================================================
// TestPortInRange 验证端口范围解析
func TestPortInRange(t *testing.T) {
tests := []struct {
port int
portsStr string
expected bool
}{
{80, "80", true},
{80, "80,443", true},
{8080, "8000-9000", true},
{7999, "8000-9000", false},
{443, "80,443,8080", true},
{22, "80,443,8080", false},
}
for _, tt := range tests {
result := portfinger.PortInRange(tt.port, tt.portsStr)
if result != tt.expected {
t.Errorf("PortInRange(%d, %q) = %v, want %v",
tt.port, tt.portsStr, result, tt.expected)
}
}
t.Log("✓ 端口范围解析功能正常")
}
// =============================================================================
// 测试7:真实场景模拟
// =============================================================================
// TestRealWorldScenario_CommonPorts 验证常见端口的探测器配置
func TestRealWorldScenario_CommonPorts(t *testing.T) {
v := portfinger.GetGlobalVScan()
scenarios := []struct {
port int
description string
}{
{80, "HTTP"},
{443, "HTTPS"},
{8080, "HTTP-Alt"},
{8443, "HTTPS-Alt"},
}
for _, s := range scenarios {
probes := v.GetProbesForPort(s.port)
sslProbes := v.GetSSLProbesForPort(s.port)
total := len(probes) + len(sslProbes)
t.Logf("端口 %d (%s): ports=%d, sslports=%d, 总计=%d",
s.port, s.description, len(probes), len(sslProbes), total)
}
}