mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00

架构优化: - 简化ScanStrategy接口,从8个方法减少到3个 - 移除不必要的Scanner结构体包装,改为直接函数调用 - 合并scheduleScanTask和executeSingleScan为单一函数 - 移除prepareScanTasks中间层,采用流式处理避免预构建任务列表 - 移除ScanTask结构体,减少内存分配 性能提升: - 流式任务执行,降低内存占用 - 统一资源管理,简化并发控制 - 减少函数调用链层次,提高执行效率 国际化完善: - 新增5个扫描流程相关的双语消息定义 - 所有硬编码中文字符串替换为i18n调用 - 完整支持中英文扫描模式选择和错误提示 代码质量: - 从187行减少到166行,函数数量从9个减少到7个 - 职责更清晰,耦合度更低,可维护性提升 - 保持向后兼容,核心功能完整
167 lines
4.4 KiB
Go
167 lines
4.4 KiB
Go
package core
|
||
|
||
import (
|
||
"fmt"
|
||
"github.com/shadow1ng/fscan/common"
|
||
"github.com/shadow1ng/fscan/common/i18n"
|
||
"github.com/shadow1ng/fscan/webscan/lib"
|
||
"strconv"
|
||
"sync"
|
||
"sync/atomic"
|
||
)
|
||
|
||
|
||
// ScanStrategy 定义扫描策略接口(简化版)
|
||
type ScanStrategy interface {
|
||
// 执行扫描的主要方法
|
||
Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup)
|
||
|
||
// 插件管理方法
|
||
GetPlugins() ([]string, bool)
|
||
IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool
|
||
}
|
||
|
||
// selectStrategy 根据扫描配置选择适当的扫描策略
|
||
func selectStrategy(info common.HostInfo) ScanStrategy {
|
||
switch {
|
||
case common.LocalMode:
|
||
common.LogBase(i18n.GetText("scan_mode_local_selected"))
|
||
return NewLocalScanStrategy()
|
||
case len(common.URLs) > 0:
|
||
common.LogBase(i18n.GetText("scan_mode_web_selected"))
|
||
return NewWebScanStrategy()
|
||
default:
|
||
common.LogBase(i18n.GetText("scan_mode_service_selected"))
|
||
return NewServiceScanStrategy()
|
||
}
|
||
}
|
||
|
||
// RunScan 执行整体扫描流程(简化版,移除不必要的包装)
|
||
func RunScan(info common.HostInfo) {
|
||
common.LogBase(i18n.GetText("scan_info_start"))
|
||
lib.Inithttp()
|
||
|
||
// 选择策略
|
||
strategy := selectStrategy(info)
|
||
|
||
// 并发控制初始化
|
||
ch := make(chan struct{}, common.ThreadNum)
|
||
wg := sync.WaitGroup{}
|
||
|
||
// 执行策略
|
||
strategy.Execute(info, &ch, &wg)
|
||
|
||
// 等待所有扫描完成
|
||
wg.Wait()
|
||
|
||
// 完成扫描
|
||
finishScan()
|
||
}
|
||
|
||
// finishScan 完成扫描并输出结果
|
||
func finishScan() {
|
||
// 确保进度条正确完成
|
||
if common.IsProgressActive() {
|
||
common.FinishProgressBar()
|
||
}
|
||
|
||
// 输出扫描完成信息
|
||
common.LogBase(i18n.GetText("scan_task_complete", common.End, common.Num))
|
||
}
|
||
|
||
// ExecuteScanTasks 任务执行通用框架(流式处理,无预构建任务列表)
|
||
func ExecuteScanTasks(targets []common.HostInfo, strategy ScanStrategy, ch *chan struct{}, wg *sync.WaitGroup) {
|
||
// 获取要执行的插件
|
||
pluginsToRun, isCustomMode := strategy.GetPlugins()
|
||
|
||
// 预计算任务数量用于进度条
|
||
taskCount := countApplicableTasks(targets, pluginsToRun, isCustomMode, strategy)
|
||
|
||
// 初始化进度条
|
||
if taskCount > 0 && common.ShowProgress {
|
||
description := i18n.GetText("progress_scanning_description")
|
||
common.InitProgressBar(int64(taskCount), description)
|
||
}
|
||
|
||
// 流式执行任务,避免预构建大量任务对象
|
||
for _, target := range targets {
|
||
targetPort := 0
|
||
if target.Ports != "" {
|
||
targetPort, _ = strconv.Atoi(target.Ports)
|
||
}
|
||
|
||
for _, pluginName := range pluginsToRun {
|
||
plugin, exists := common.PluginManager[pluginName]
|
||
if !exists {
|
||
continue
|
||
}
|
||
|
||
// 检查插件是否适用于当前目标
|
||
if strategy.IsPluginApplicable(plugin, targetPort, isCustomMode) {
|
||
executeScanTask(pluginName, target, ch, wg)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// countApplicableTasks 计算适用的任务数量(用于进度条初始化)
|
||
func countApplicableTasks(targets []common.HostInfo, pluginsToRun []string, isCustomMode bool, strategy ScanStrategy) int {
|
||
count := 0
|
||
for _, target := range targets {
|
||
targetPort := 0
|
||
if target.Ports != "" {
|
||
targetPort, _ = strconv.Atoi(target.Ports)
|
||
}
|
||
|
||
for _, pluginName := range pluginsToRun {
|
||
plugin, exists := common.PluginManager[pluginName]
|
||
if exists && strategy.IsPluginApplicable(plugin, targetPort, isCustomMode) {
|
||
count++
|
||
}
|
||
}
|
||
}
|
||
return count
|
||
}
|
||
|
||
|
||
// executeScanTask 执行单个扫描任务(合并原 scheduleScanTask 和 executeSingleScan)
|
||
func executeScanTask(pluginName string, target common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||
wg.Add(1)
|
||
*ch <- struct{}{} // 获取并发槽位
|
||
|
||
go func() {
|
||
defer func() {
|
||
// 捕获并记录任何可能的panic
|
||
if r := recover(); r != nil {
|
||
common.LogError(fmt.Sprintf(i18n.GetText("scan_plugin_panic"),
|
||
pluginName, target.Host, target.Ports, r))
|
||
}
|
||
|
||
// 完成任务,释放资源
|
||
wg.Done()
|
||
<-*ch // 释放并发槽位
|
||
}()
|
||
|
||
// 更新统计和进度
|
||
atomic.AddInt64(&common.Num, 1)
|
||
common.UpdateProgressBar(1)
|
||
|
||
// 执行扫描
|
||
plugin, exists := common.PluginManager[pluginName]
|
||
if !exists {
|
||
common.LogBase(fmt.Sprintf(i18n.GetText("scan_plugin_not_found"), pluginName))
|
||
return
|
||
}
|
||
|
||
if err := plugin.ScanFunc(&target); err != nil {
|
||
common.LogError(fmt.Sprintf(i18n.GetText("scan_plugin_error"), target.Host, target.Ports, err))
|
||
}
|
||
}()
|
||
}
|
||
|
||
|
||
// Scan 入口函数,向后兼容旧的调用方式
|
||
func Scan(info common.HostInfo) {
|
||
RunScan(info)
|
||
}
|