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

新增功能: - 支持通过-m icmp参数启用存活探测功能 - 与现有-ao参数功能等价,提供更直观的使用方式 - 添加参数冲突检查,当同时使用-ao和-m icmp时给出友好提示 - 完善参数验证,将icmp添加到有效扫描模式列表 技术实现: - 扩展ValidationParser支持icmp模式验证 - 修改Scanner策略选择逻辑支持icmp模式 - 新增参数冲突检查函数checkParameterConflicts - 更新帮助信息和国际化消息支持 向后兼容: - 保持-ao参数原有功能不变 - 两种参数方式都能正确触发存活探测 - 支持中英文双语界面和提示信息
170 lines
4.5 KiB
Go
170 lines
4.5 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.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 {
|
||
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)
|
||
}
|