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 IsPluginApplicableByName(pluginName string, targetPort int, isCustomMode bool) bool } // selectStrategy 根据扫描配置选择适当的扫描策略 func selectStrategy(info common.HostInfo) ScanStrategy { switch { case common.AliveOnly || common.ScanMode == "icmp": common.LogBase(i18n.GetText("scan_mode_alive_selected")) return NewAliveScanStrategy() 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 { if !GlobalPluginAdapter.PluginExists(pluginName) { continue } // 检查插件是否适用于当前目标 if strategy.IsPluginApplicableByName(pluginName, 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 { if GlobalPluginAdapter.PluginExists(pluginName) && strategy.IsPluginApplicableByName(pluginName, 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() { // 开始监控插件任务 monitor := common.GetConcurrencyMonitor() monitor.StartPluginTask() defer func() { // 捕获并记录任何可能的panic if r := recover(); r != nil { common.LogError(fmt.Sprintf(i18n.GetText("scan_plugin_panic"), pluginName, target.Host, target.Ports, r)) } // 完成任务,释放资源 monitor.FinishPluginTask() wg.Done() <-*ch // 释放并发槽位 }() // 更新统计和进度 atomic.AddInt64(&common.Num, 1) common.UpdateProgressBar(1) // 执行扫描(使用新插件系统) if err := GlobalPluginAdapter.ScanWithPlugin(pluginName, &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) }