Files
fscan/core/portfinger/scanner_core.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

124 lines
2.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 portfinger
import (
_ "embed"
"strings"
"sync"
)
// ProbeString 嵌入的nmap服务探测数据
//
//go:embed nmap-service-probes.txt
var ProbeString string
// 全局VScan实例(使用sync.Once确保只初始化一次)
var (
globalVScan VScan
globalNull *Probe
globalCommon *Probe
vscanOnce sync.Once
)
// Init 初始化VScan对象
func (vs *VScan) Init() {
vs.parseProbesFromContent(ProbeString)
vs.parseProbesToMapKName()
vs.SetusedProbes()
vs.compileFallbacks() // 编译 fallback 数组
}
// compileFallbacks 编译所有探测器的 fallback 数组
// 参考 Nmap 的 AllProbes::compileFallbacks() 实现
func (vs *VScan) compileFallbacks() {
// 获取 NULL 探测器指针
var nullProbe *Probe
if np, ok := vs.ProbesMapKName["NULL"]; ok {
nullProbe = &np
// NULL 探测器的 fallback 只包含自身
nullProbe.Fallbacks[0] = nullProbe
vs.ProbesMapKName["NULL"] = *nullProbe
}
// 遍历所有探测器,编译 fallback 数组
for i := range vs.Probes {
probe := &vs.Probes[i]
idx := 0
// fallbacks[0] = 自身
probe.Fallbacks[idx] = probe
idx++
if probe.Fallback == "" {
// 无 fallback 指令:TCP 使用 [自身, NULL]UDP 使用 [自身]
if probe.Protocol == "tcp" && nullProbe != nil {
probe.Fallbacks[idx] = nullProbe
}
} else {
// 有 fallback 指令:解析逗号分隔的探测器名称
fallbackNames := strings.Split(probe.Fallback, ",")
for _, name := range fallbackNames {
name = strings.TrimSpace(name)
if name == "" {
continue
}
if idx >= MaxFallbacks {
break
}
if fbProbe, ok := vs.ProbesMapKName[name]; ok {
probe.Fallbacks[idx] = &fbProbe
idx++
}
}
// TCP 探测器在末尾添加 NULL 探测器
if probe.Protocol == "tcp" && nullProbe != nil && idx < MaxFallbacks {
probe.Fallbacks[idx] = nullProbe
}
}
}
// 更新 ProbesMapKName 中的探测器(因为我们修改了 Fallbacks)
for i := range vs.Probes {
vs.ProbesMapKName[vs.Probes[i].Name] = vs.Probes[i]
}
}
// InitializeGlobalVScan 初始化全局VScan实例(线程安全,只执行一次)
func InitializeGlobalVScan() {
vscanOnce.Do(func() {
globalVScan = VScan{}
globalVScan.Init()
// 获取并检查 NULL 探测器
if nullProbe, ok := globalVScan.ProbesMapKName["NULL"]; ok {
globalNull = &nullProbe
}
// 获取并检查 GenericLines 探测器
if genericProbe, ok := globalVScan.ProbesMapKName["GenericLines"]; ok {
globalCommon = &genericProbe
}
})
}
// GetGlobalVScan 获取全局VScan实例
func GetGlobalVScan() *VScan {
InitializeGlobalVScan() // 确保已初始化
return &globalVScan
}
// GetNullProbe 获取NULL探测器
func GetNullProbe() *Probe {
InitializeGlobalVScan() // 确保已初始化
return globalNull
}
// GetCommonProbe 获取通用探测器
func GetCommonProbe() *Probe {
InitializeGlobalVScan() // 确保已初始化
return globalCommon
}
func init() {
InitializeGlobalVScan()
}