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

新增功能: - 添加-ao参数启用存活探测模式,专注于ICMP ping检测 - 实现AliveScanner专用扫描器,提供详细统计信息 - 集成到Scanner架构,支持与其他扫描模式无缝切换 - 完善i18n国际化支持,覆盖中英文界面 技术实现: - 新增core/AliveScanner.go实现专用存活检测逻辑 - 扩展Scanner.go选择策略支持存活探测模式 - 优化目标解析和错误处理机制 - 提供成功率、耗时等详细扫描统计 使用场景: - 快速批量主机存活性验证 - 网络拓扑发现前期探测 - 大规模网络资产盘点预检
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.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)
|
||
}
|