mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
feat: 实现存活探测模式(-ao)支持快速主机存活状态检测
新增功能: - 添加-ao参数启用存活探测模式,专注于ICMP ping检测 - 实现AliveScanner专用扫描器,提供详细统计信息 - 集成到Scanner架构,支持与其他扫描模式无缝切换 - 完善i18n国际化支持,覆盖中英文界面 技术实现: - 新增core/AliveScanner.go实现专用存活检测逻辑 - 扩展Scanner.go选择策略支持存活探测模式 - 优化目标解析和错误处理机制 - 提供成功率、耗时等详细扫描统计 使用场景: - 快速批量主机存活性验证 - 网络拓扑发现前期探测 - 大规模网络资产盘点预检
This commit is contained in:
parent
6c93129cb1
commit
78f81610cd
@ -148,6 +148,7 @@ func Flag(Info *HostInfo) {
|
|||||||
flag.BoolVar(&DisablePing, "np", false, i18n.GetText("flag_disable_ping"))
|
flag.BoolVar(&DisablePing, "np", false, i18n.GetText("flag_disable_ping"))
|
||||||
flag.BoolVar(&EnableFingerprint, "fingerprint", false, i18n.GetText("flag_enable_fingerprint"))
|
flag.BoolVar(&EnableFingerprint, "fingerprint", false, i18n.GetText("flag_enable_fingerprint"))
|
||||||
flag.BoolVar(&LocalMode, "local", false, i18n.GetText("flag_local_mode"))
|
flag.BoolVar(&LocalMode, "local", false, i18n.GetText("flag_local_mode"))
|
||||||
|
flag.BoolVar(&AliveOnly, "ao", false, i18n.GetText("flag_alive_only"))
|
||||||
|
|
||||||
// ═════════════════════════════════════════════════
|
// ═════════════════════════════════════════════════
|
||||||
// 认证与凭据参数
|
// 认证与凭据参数
|
||||||
|
@ -40,6 +40,7 @@ var (
|
|||||||
Timeout int64 // 直接映射到base.Timeout
|
Timeout int64 // 直接映射到base.Timeout
|
||||||
DisablePing bool // 直接映射到base.DisablePing
|
DisablePing bool // 直接映射到base.DisablePing
|
||||||
LocalMode bool // 直接映射到base.LocalMode
|
LocalMode bool // 直接映射到base.LocalMode
|
||||||
|
AliveOnly bool // 仅存活探测模式
|
||||||
)
|
)
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
@ -70,6 +70,10 @@ var FlagMessages = map[string]map[string]string{
|
|||||||
LangZH: "本地扫描模式",
|
LangZH: "本地扫描模式",
|
||||||
LangEN: "Local scan mode",
|
LangEN: "Local scan mode",
|
||||||
},
|
},
|
||||||
|
"flag_alive_only": {
|
||||||
|
LangZH: "仅进行存活探测",
|
||||||
|
LangEN: "Alive detection only",
|
||||||
|
},
|
||||||
"flag_username": {
|
"flag_username": {
|
||||||
LangZH: "用户名",
|
LangZH: "用户名",
|
||||||
LangEN: "Username",
|
LangEN: "Username",
|
||||||
|
@ -280,4 +280,8 @@ var ParseMessages = map[string]map[string]string{
|
|||||||
LangZH: "无效的目标地址格式: %s",
|
LangZH: "无效的目标地址格式: %s",
|
||||||
LangEN: "Invalid target address format: %s",
|
LangEN: "Invalid target address format: %s",
|
||||||
},
|
},
|
||||||
|
"parse_error_no_hosts": {
|
||||||
|
LangZH: "解析后没有找到有效的目标主机",
|
||||||
|
LangEN: "No valid target hosts found after parsing",
|
||||||
|
},
|
||||||
}
|
}
|
@ -14,6 +14,10 @@ var ScanMessages = map[string]map[string]string{
|
|||||||
LangZH: "已选择服务扫描模式",
|
LangZH: "已选择服务扫描模式",
|
||||||
LangEN: "Service scan mode selected",
|
LangEN: "Service scan mode selected",
|
||||||
},
|
},
|
||||||
|
"scan_mode_alive_selected": {
|
||||||
|
LangZH: "已选择存活探测模式",
|
||||||
|
LangEN: "Alive detection mode selected",
|
||||||
|
},
|
||||||
"scan_mode_local_selected": {
|
"scan_mode_local_selected": {
|
||||||
LangZH: "已选择本地扫描模式",
|
LangZH: "已选择本地扫描模式",
|
||||||
LangEN: "Local scan mode selected",
|
LangEN: "Local scan mode selected",
|
||||||
@ -154,6 +158,58 @@ var ScanMessages = map[string]map[string]string{
|
|||||||
LangZH: "存活主机数量: %d",
|
LangZH: "存活主机数量: %d",
|
||||||
LangEN: "Alive hosts count: %d",
|
LangEN: "Alive hosts count: %d",
|
||||||
},
|
},
|
||||||
|
"scan_strategy_alive_name": {
|
||||||
|
LangZH: "存活探测",
|
||||||
|
LangEN: "Alive Detection",
|
||||||
|
},
|
||||||
|
"scan_strategy_alive_desc": {
|
||||||
|
LangZH: "快速探测主机存活状态",
|
||||||
|
LangEN: "Fast detection of host alive status",
|
||||||
|
},
|
||||||
|
"scan_alive_start": {
|
||||||
|
LangZH: "开始存活探测",
|
||||||
|
LangEN: "Starting alive detection",
|
||||||
|
},
|
||||||
|
"scan_alive_single_target": {
|
||||||
|
LangZH: "目标主机: %s",
|
||||||
|
LangEN: "Target host: %s",
|
||||||
|
},
|
||||||
|
"scan_alive_multiple_targets": {
|
||||||
|
LangZH: "目标主机数量: %d (示例: %s)",
|
||||||
|
LangEN: "Target hosts count: %d (example: %s)",
|
||||||
|
},
|
||||||
|
"scan_alive_summary_title": {
|
||||||
|
LangZH: "存活探测结果摘要",
|
||||||
|
LangEN: "Alive Detection Summary",
|
||||||
|
},
|
||||||
|
"scan_alive_total_hosts": {
|
||||||
|
LangZH: "总主机数: %d",
|
||||||
|
LangEN: "Total hosts: %d",
|
||||||
|
},
|
||||||
|
"scan_alive_hosts_found": {
|
||||||
|
LangZH: "存活主机: %d",
|
||||||
|
LangEN: "Alive hosts: %d",
|
||||||
|
},
|
||||||
|
"scan_alive_dead_hosts": {
|
||||||
|
LangZH: "死亡主机: %d",
|
||||||
|
LangEN: "Dead hosts: %d",
|
||||||
|
},
|
||||||
|
"scan_alive_success_rate": {
|
||||||
|
LangZH: "存活率: %.2f%%",
|
||||||
|
LangEN: "Success rate: %.2f%%",
|
||||||
|
},
|
||||||
|
"scan_alive_duration": {
|
||||||
|
LangZH: "扫描耗时: %v",
|
||||||
|
LangEN: "Scan duration: %v",
|
||||||
|
},
|
||||||
|
"scan_alive_hosts_list": {
|
||||||
|
LangZH: "存活主机列表:",
|
||||||
|
LangEN: "Alive hosts list:",
|
||||||
|
},
|
||||||
|
"target_alive": {
|
||||||
|
LangZH: "存活主机: %s (%s)",
|
||||||
|
LangEN: "Alive host: %s (%s)",
|
||||||
|
},
|
||||||
|
|
||||||
// ========================= 进度条消息 =========================
|
// ========================= 进度条消息 =========================
|
||||||
"progress_scanning_description": {
|
"progress_scanning_description": {
|
||||||
|
160
Core/AliveScanner.go
Normal file
160
Core/AliveScanner.go
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
"github.com/shadow1ng/fscan/common/parsers"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
AliveScanner.go - 存活探测扫描器
|
||||||
|
|
||||||
|
专门用于主机存活探测,仅执行ICMP/Ping检测,
|
||||||
|
快速识别网络中的存活主机,不进行端口扫描。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AliveScanStrategy 存活探测扫描策略
|
||||||
|
type AliveScanStrategy struct {
|
||||||
|
*BaseScanStrategy
|
||||||
|
startTime time.Time
|
||||||
|
stats AliveStats
|
||||||
|
}
|
||||||
|
|
||||||
|
// AliveStats 存活探测统计信息
|
||||||
|
type AliveStats struct {
|
||||||
|
TotalHosts int // 总主机数
|
||||||
|
AliveHosts int // 存活主机数
|
||||||
|
DeadHosts int // 死亡主机数
|
||||||
|
ScanDuration time.Duration // 扫描耗时
|
||||||
|
SuccessRate float64 // 成功率
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAliveScanStrategy 创建新的存活探测扫描策略
|
||||||
|
func NewAliveScanStrategy() *AliveScanStrategy {
|
||||||
|
return &AliveScanStrategy{
|
||||||
|
BaseScanStrategy: NewBaseScanStrategy("存活探测", FilterNone),
|
||||||
|
startTime: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name 返回策略名称
|
||||||
|
func (s *AliveScanStrategy) Name() string {
|
||||||
|
return i18n.GetText("scan_strategy_alive_name")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Description 返回策略描述
|
||||||
|
func (s *AliveScanStrategy) Description() string {
|
||||||
|
return i18n.GetText("scan_strategy_alive_desc")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute 执行存活探测扫描策略
|
||||||
|
func (s *AliveScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
|
// 验证扫描目标
|
||||||
|
if info.Host == "" {
|
||||||
|
common.LogError(i18n.GetText("parse_error_target_empty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出存活探测开始信息
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_start"))
|
||||||
|
|
||||||
|
// 执行存活探测
|
||||||
|
s.performAliveScan(info)
|
||||||
|
|
||||||
|
// 输出统计信息
|
||||||
|
s.outputStats()
|
||||||
|
}
|
||||||
|
|
||||||
|
// performAliveScan 执行存活探测
|
||||||
|
func (s *AliveScanStrategy) performAliveScan(info common.HostInfo) {
|
||||||
|
// 解析目标主机
|
||||||
|
hosts, err := parsers.ParseIP(info.Host, common.HostsFile, common.ExcludeHosts)
|
||||||
|
if err != nil {
|
||||||
|
common.LogError(i18n.GetText("parse_error_target_failed", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hosts) == 0 {
|
||||||
|
common.LogError(i18n.GetText("parse_error_no_hosts"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化统计信息
|
||||||
|
s.stats.TotalHosts = len(hosts)
|
||||||
|
s.stats.AliveHosts = 0
|
||||||
|
s.stats.DeadHosts = 0
|
||||||
|
|
||||||
|
// 显示扫描信息
|
||||||
|
if len(hosts) == 1 {
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_single_target", hosts[0]))
|
||||||
|
} else {
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_multiple_targets", len(hosts), hosts[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空之前的存活主机记录
|
||||||
|
AliveHosts = nil
|
||||||
|
for k := range ExistHosts {
|
||||||
|
delete(ExistHosts, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行存活检测
|
||||||
|
aliveList := CheckLive(hosts, false) // 使用ICMP探测
|
||||||
|
|
||||||
|
// 更新统计信息
|
||||||
|
s.stats.AliveHosts = len(aliveList)
|
||||||
|
s.stats.DeadHosts = s.stats.TotalHosts - s.stats.AliveHosts
|
||||||
|
s.stats.ScanDuration = time.Since(s.startTime)
|
||||||
|
|
||||||
|
if s.stats.TotalHosts > 0 {
|
||||||
|
s.stats.SuccessRate = float64(s.stats.AliveHosts) / float64(s.stats.TotalHosts) * 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// outputStats 输出详细统计信息
|
||||||
|
func (s *AliveScanStrategy) outputStats() {
|
||||||
|
// 输出分隔线
|
||||||
|
common.LogBase("=" + strings.Repeat("=", 60))
|
||||||
|
|
||||||
|
// 输出扫描结果摘要
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_summary_title"))
|
||||||
|
|
||||||
|
// 基础统计
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_total_hosts", s.stats.TotalHosts))
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_hosts_found", s.stats.AliveHosts))
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_dead_hosts", s.stats.DeadHosts))
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_success_rate", s.stats.SuccessRate))
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_duration", s.stats.ScanDuration.Round(time.Millisecond)))
|
||||||
|
|
||||||
|
// 如果有存活主机,显示详细列表
|
||||||
|
if s.stats.AliveHosts > 0 {
|
||||||
|
common.LogBase("")
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_hosts_list"))
|
||||||
|
|
||||||
|
for i, host := range AliveHosts {
|
||||||
|
common.LogSuccess(fmt.Sprintf(" [%d] %s", i+1, host))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出分隔线
|
||||||
|
common.LogBase("=" + strings.Repeat("=", 60))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareTargets 存活探测不需要准备扫描目标
|
||||||
|
func (s *AliveScanStrategy) PrepareTargets(info common.HostInfo) []common.HostInfo {
|
||||||
|
// 存活探测不需要返回目标列表,因为它不进行后续扫描
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlugins 存活探测不使用插件
|
||||||
|
func (s *AliveScanStrategy) GetPlugins() ([]string, bool) {
|
||||||
|
return []string{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPluginApplicable 存活探测不适用任何插件
|
||||||
|
func (s *AliveScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
||||||
|
return false
|
||||||
|
}
|
@ -24,6 +24,9 @@ type ScanStrategy interface {
|
|||||||
// selectStrategy 根据扫描配置选择适当的扫描策略
|
// selectStrategy 根据扫描配置选择适当的扫描策略
|
||||||
func selectStrategy(info common.HostInfo) ScanStrategy {
|
func selectStrategy(info common.HostInfo) ScanStrategy {
|
||||||
switch {
|
switch {
|
||||||
|
case common.AliveOnly:
|
||||||
|
common.LogBase(i18n.GetText("scan_mode_alive_selected"))
|
||||||
|
return NewAliveScanStrategy()
|
||||||
case common.LocalMode:
|
case common.LocalMode:
|
||||||
common.LogBase(i18n.GetText("scan_mode_local_selected"))
|
common.LogBase(i18n.GetText("scan_mode_local_selected"))
|
||||||
return NewLocalScanStrategy()
|
return NewLocalScanStrategy()
|
||||||
|
Loading…
Reference in New Issue
Block a user