mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
enhance: 增强进度条显示和扫描配置功能
- 在扫描开始时显示详细配置信息(-t, -time, -mt, -gt参数) - 端口扫描进度条显示线程数配置 - 进度条实时显示插件和连接并发状态 - 添加ConcurrencyMonitor并发监控系统 - 提升mt参数默认值从10到50以提高扫描性能 - 移除端口范围限制,支持全端口扫描(1-65535) - 完善中英文国际化支持
This commit is contained in:
parent
de286026e8
commit
8a2c9737f3
191
Common/ConcurrencyMonitor.go
Normal file
191
Common/ConcurrencyMonitor.go
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
ConcurrencyMonitor.go - 并发监控器
|
||||||
|
|
||||||
|
监控两个层级的并发:
|
||||||
|
1. 主扫描器线程数 (-t 参数控制)
|
||||||
|
2. 插件内连接线程数 (-mt 参数控制)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ConcurrencyMonitor 并发监控器
|
||||||
|
type ConcurrencyMonitor struct {
|
||||||
|
// 主扫描器层级
|
||||||
|
activePluginTasks int64 // 当前活跃的插件任务数
|
||||||
|
totalPluginTasks int64 // 总插件任务数
|
||||||
|
|
||||||
|
// 插件内连接层级 (每个插件的连接线程数)
|
||||||
|
pluginConnections sync.Map // map[string]*PluginConnectionInfo
|
||||||
|
|
||||||
|
mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginConnectionInfo 单个插件的连接信息
|
||||||
|
type PluginConnectionInfo struct {
|
||||||
|
PluginName string // 插件名称
|
||||||
|
Target string // 目标地址
|
||||||
|
ActiveConnections int64 // 当前活跃连接数
|
||||||
|
TotalConnections int64 // 总连接数
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
globalConcurrencyMonitor *ConcurrencyMonitor
|
||||||
|
concurrencyMutex sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetConcurrencyMonitor 获取全局并发监控器
|
||||||
|
func GetConcurrencyMonitor() *ConcurrencyMonitor {
|
||||||
|
concurrencyMutex.Do(func() {
|
||||||
|
globalConcurrencyMonitor = &ConcurrencyMonitor{
|
||||||
|
activePluginTasks: 0,
|
||||||
|
totalPluginTasks: 0,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return globalConcurrencyMonitor
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 主扫描器层级监控
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// StartPluginTask 开始插件任务
|
||||||
|
func (m *ConcurrencyMonitor) StartPluginTask() {
|
||||||
|
atomic.AddInt64(&m.activePluginTasks, 1)
|
||||||
|
atomic.AddInt64(&m.totalPluginTasks, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FinishPluginTask 完成插件任务
|
||||||
|
func (m *ConcurrencyMonitor) FinishPluginTask() {
|
||||||
|
atomic.AddInt64(&m.activePluginTasks, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPluginTaskStats 获取插件任务统计
|
||||||
|
func (m *ConcurrencyMonitor) GetPluginTaskStats() (active int64, total int64) {
|
||||||
|
return atomic.LoadInt64(&m.activePluginTasks), atomic.LoadInt64(&m.totalPluginTasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 插件内连接层级监控
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// StartConnection 开始连接
|
||||||
|
func (m *ConcurrencyMonitor) StartConnection(pluginName, target string) {
|
||||||
|
key := fmt.Sprintf("%s@%s", pluginName, target)
|
||||||
|
|
||||||
|
value, _ := m.pluginConnections.LoadOrStore(key, &PluginConnectionInfo{
|
||||||
|
PluginName: pluginName,
|
||||||
|
Target: target,
|
||||||
|
})
|
||||||
|
|
||||||
|
info := value.(*PluginConnectionInfo)
|
||||||
|
atomic.AddInt64(&info.ActiveConnections, 1)
|
||||||
|
atomic.AddInt64(&info.TotalConnections, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FinishConnection 完成连接
|
||||||
|
func (m *ConcurrencyMonitor) FinishConnection(pluginName, target string) {
|
||||||
|
key := fmt.Sprintf("%s@%s", pluginName, target)
|
||||||
|
|
||||||
|
if value, ok := m.pluginConnections.Load(key); ok {
|
||||||
|
info := value.(*PluginConnectionInfo)
|
||||||
|
atomic.AddInt64(&info.ActiveConnections, -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConnectionStats 获取所有插件连接统计
|
||||||
|
func (m *ConcurrencyMonitor) GetConnectionStats() map[string]*PluginConnectionInfo {
|
||||||
|
stats := make(map[string]*PluginConnectionInfo)
|
||||||
|
|
||||||
|
m.pluginConnections.Range(func(key, value interface{}) bool {
|
||||||
|
keyStr := key.(string)
|
||||||
|
info := value.(*PluginConnectionInfo)
|
||||||
|
|
||||||
|
// 只返回当前活跃的连接
|
||||||
|
if atomic.LoadInt64(&info.ActiveConnections) > 0 {
|
||||||
|
stats[keyStr] = &PluginConnectionInfo{
|
||||||
|
PluginName: info.PluginName,
|
||||||
|
Target: info.Target,
|
||||||
|
ActiveConnections: atomic.LoadInt64(&info.ActiveConnections),
|
||||||
|
TotalConnections: atomic.LoadInt64(&info.TotalConnections),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTotalActiveConnections 获取总活跃连接数
|
||||||
|
func (m *ConcurrencyMonitor) GetTotalActiveConnections() int64 {
|
||||||
|
var total int64
|
||||||
|
|
||||||
|
m.pluginConnections.Range(func(key, value interface{}) bool {
|
||||||
|
info := value.(*PluginConnectionInfo)
|
||||||
|
total += atomic.LoadInt64(&info.ActiveConnections)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset 重置监控器
|
||||||
|
func (m *ConcurrencyMonitor) Reset() {
|
||||||
|
atomic.StoreInt64(&m.activePluginTasks, 0)
|
||||||
|
atomic.StoreInt64(&m.totalPluginTasks, 0)
|
||||||
|
|
||||||
|
m.pluginConnections.Range(func(key, value interface{}) bool {
|
||||||
|
m.pluginConnections.Delete(key)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConcurrencyStatus 获取并发状态字符串
|
||||||
|
func (m *ConcurrencyMonitor) GetConcurrencyStatus() string {
|
||||||
|
activePlugins, _ := m.GetPluginTaskStats()
|
||||||
|
totalConnections := m.GetTotalActiveConnections()
|
||||||
|
|
||||||
|
if activePlugins == 0 && totalConnections == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalConnections == 0 {
|
||||||
|
return fmt.Sprintf("%s:%d", i18n.GetText("concurrency_plugin"), activePlugins)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s:%d %s:%d",
|
||||||
|
i18n.GetText("concurrency_plugin"), activePlugins,
|
||||||
|
i18n.GetText("concurrency_connection"), totalConnections)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDetailedStatus 获取详细的并发状态
|
||||||
|
func (m *ConcurrencyMonitor) GetDetailedStatus() string {
|
||||||
|
activePlugins, _ := m.GetPluginTaskStats()
|
||||||
|
connectionStats := m.GetConnectionStats()
|
||||||
|
|
||||||
|
if activePlugins == 0 && len(connectionStats) == 0 {
|
||||||
|
return i18n.GetText("concurrency_no_active_tasks")
|
||||||
|
}
|
||||||
|
|
||||||
|
status := fmt.Sprintf("%s: %d", i18n.GetText("concurrency_plugin_tasks"), activePlugins)
|
||||||
|
|
||||||
|
if len(connectionStats) > 0 {
|
||||||
|
status += " | " + i18n.GetText("concurrency_connection_details") + ": "
|
||||||
|
first := true
|
||||||
|
for _, info := range connectionStats {
|
||||||
|
if !first {
|
||||||
|
status += ", "
|
||||||
|
}
|
||||||
|
status += fmt.Sprintf("%s@%s:%d", info.PluginName, info.Target, info.ActiveConnections)
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status
|
||||||
|
}
|
@ -142,7 +142,7 @@ func Flag(Info *HostInfo) {
|
|||||||
flag.StringVar(&ScanMode, "m", "all", i18n.GetText("flag_scan_mode"))
|
flag.StringVar(&ScanMode, "m", "all", i18n.GetText("flag_scan_mode"))
|
||||||
flag.IntVar(&ThreadNum, "t", 600, i18n.GetText("flag_thread_num"))
|
flag.IntVar(&ThreadNum, "t", 600, i18n.GetText("flag_thread_num"))
|
||||||
flag.Int64Var(&Timeout, "time", 3, i18n.GetText("flag_timeout"))
|
flag.Int64Var(&Timeout, "time", 3, i18n.GetText("flag_timeout"))
|
||||||
flag.IntVar(&ModuleThreadNum, "mt", 10, i18n.GetText("flag_module_thread_num"))
|
flag.IntVar(&ModuleThreadNum, "mt", 50, i18n.GetText("flag_module_thread_num"))
|
||||||
flag.Int64Var(&GlobalTimeout, "gt", 180, i18n.GetText("flag_global_timeout"))
|
flag.Int64Var(&GlobalTimeout, "gt", 180, i18n.GetText("flag_global_timeout"))
|
||||||
// LiveTop 参数已移除,改为智能控制
|
// LiveTop 参数已移除,改为智能控制
|
||||||
flag.BoolVar(&DisablePing, "np", false, i18n.GetText("flag_disable_ping"))
|
flag.BoolVar(&DisablePing, "np", false, i18n.GetText("flag_disable_ping"))
|
||||||
|
@ -392,6 +392,12 @@ func showParseSummary(config *parsers.ParsedConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 显示扫描配置
|
||||||
|
LogBase(i18n.GetText("scan_config_thread_num", ThreadNum))
|
||||||
|
LogBase(i18n.GetText("scan_config_timeout", Timeout))
|
||||||
|
LogBase(i18n.GetText("scan_config_module_thread_num", ModuleThreadNum))
|
||||||
|
LogBase(i18n.GetText("scan_config_global_timeout", GlobalTimeout))
|
||||||
|
|
||||||
// 显示网络配置
|
// 显示网络配置
|
||||||
if config.Network != nil {
|
if config.Network != nil {
|
||||||
if config.Network.HttpProxy != "" {
|
if config.Network.HttpProxy != "" {
|
||||||
@ -400,9 +406,6 @@ func showParseSummary(config *parsers.ParsedConfig) {
|
|||||||
if config.Network.Socks5Proxy != "" {
|
if config.Network.Socks5Proxy != "" {
|
||||||
LogBase(i18n.GetText("network_socks5_proxy", config.Network.Socks5Proxy))
|
LogBase(i18n.GetText("network_socks5_proxy", config.Network.Socks5Proxy))
|
||||||
}
|
}
|
||||||
if config.Network.Timeout > 0 {
|
|
||||||
LogBase(i18n.GetText("network_timeout", config.Network.Timeout))
|
|
||||||
}
|
|
||||||
if config.Network.WebTimeout > 0 {
|
if config.Network.WebTimeout > 0 {
|
||||||
LogBase(i18n.GetText("network_web_timeout", config.Network.WebTimeout))
|
LogBase(i18n.GetText("network_web_timeout", config.Network.WebTimeout))
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,9 @@ func (pm *ProgressManager) generateProgressBar() string {
|
|||||||
percentage := float64(pm.current) / float64(pm.total) * 100
|
percentage := float64(pm.current) / float64(pm.total) * 100
|
||||||
elapsed := time.Since(pm.startTime)
|
elapsed := time.Since(pm.startTime)
|
||||||
|
|
||||||
|
// 获取并发状态
|
||||||
|
concurrencyStatus := GetConcurrencyMonitor().GetConcurrencyStatus()
|
||||||
|
|
||||||
// 计算预估剩余时间
|
// 计算预估剩余时间
|
||||||
var eta string
|
var eta string
|
||||||
if pm.current > 0 {
|
if pm.current > 0 {
|
||||||
@ -194,8 +197,16 @@ func (pm *ProgressManager) generateProgressBar() string {
|
|||||||
bar += "|"
|
bar += "|"
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s %6.1f%% %s (%d/%d)%s%s",
|
// 构建基础进度条
|
||||||
|
baseProgress := fmt.Sprintf("%s %6.1f%% %s (%d/%d)%s%s",
|
||||||
pm.description, percentage, bar, pm.current, pm.total, speedStr, eta)
|
pm.description, percentage, bar, pm.current, pm.total, speedStr, eta)
|
||||||
|
|
||||||
|
// 添加并发状态
|
||||||
|
if concurrencyStatus != "" {
|
||||||
|
return fmt.Sprintf("%s [%s]", baseProgress, concurrencyStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseProgress
|
||||||
}
|
}
|
||||||
|
|
||||||
// showCompletionInfo 显示完成信息
|
// showCompletionInfo 显示完成信息
|
||||||
|
@ -224,6 +224,10 @@ var ScanMessages = map[string]map[string]string{
|
|||||||
LangZH: "端口扫描",
|
LangZH: "端口扫描",
|
||||||
LangEN: "Port Scanning",
|
LangEN: "Port Scanning",
|
||||||
},
|
},
|
||||||
|
"progress_port_scanning_with_threads": {
|
||||||
|
LangZH: "端口扫描 (线程:%d)",
|
||||||
|
LangEN: "Port Scanning (Threads:%d)",
|
||||||
|
},
|
||||||
"progress_scan_completed": {
|
"progress_scan_completed": {
|
||||||
LangZH: "扫描完成:",
|
LangZH: "扫描完成:",
|
||||||
LangEN: "Scan Completed:",
|
LangEN: "Scan Completed:",
|
||||||
@ -236,4 +240,44 @@ var ScanMessages = map[string]map[string]string{
|
|||||||
LangZH: "开放端口",
|
LangZH: "开放端口",
|
||||||
LangEN: "Open Ports",
|
LangEN: "Open Ports",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ========================= 并发状态消息 =========================
|
||||||
|
"concurrency_plugin": {
|
||||||
|
LangZH: "插件",
|
||||||
|
LangEN: "Plugins",
|
||||||
|
},
|
||||||
|
"concurrency_connection": {
|
||||||
|
LangZH: "连接",
|
||||||
|
LangEN: "Conns",
|
||||||
|
},
|
||||||
|
"concurrency_plugin_tasks": {
|
||||||
|
LangZH: "活跃插件任务",
|
||||||
|
LangEN: "Active Plugin Tasks",
|
||||||
|
},
|
||||||
|
"concurrency_connection_details": {
|
||||||
|
LangZH: "连接详情",
|
||||||
|
LangEN: "Connection Details",
|
||||||
|
},
|
||||||
|
"concurrency_no_active_tasks": {
|
||||||
|
LangZH: "无活跃任务",
|
||||||
|
LangEN: "No Active Tasks",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 扫描配置消息 =========================
|
||||||
|
"scan_config_thread_num": {
|
||||||
|
LangZH: "端口扫描线程数: %d",
|
||||||
|
LangEN: "Port scan threads: %d",
|
||||||
|
},
|
||||||
|
"scan_config_timeout": {
|
||||||
|
LangZH: "连接超时: %ds",
|
||||||
|
LangEN: "Connection timeout: %ds",
|
||||||
|
},
|
||||||
|
"scan_config_module_thread_num": {
|
||||||
|
LangZH: "插件内线程数: %d",
|
||||||
|
LangEN: "Plugin threads: %d",
|
||||||
|
},
|
||||||
|
"scan_config_global_timeout": {
|
||||||
|
LangZH: "单个插件全局超时: %ds",
|
||||||
|
LangEN: "Plugin global timeout: %ds",
|
||||||
|
},
|
||||||
}
|
}
|
@ -290,11 +290,6 @@ func parsePortRange(rangeStr string) []int {
|
|||||||
var ports []int
|
var ports []int
|
||||||
for i := start; i <= end; i++ {
|
for i := start; i <= end; i++ {
|
||||||
ports = append(ports, i)
|
ports = append(ports, i)
|
||||||
|
|
||||||
// 限制端口范围大小
|
|
||||||
if len(ports) > SimpleMaxPortRange {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ports
|
return ports
|
||||||
|
@ -184,7 +184,6 @@ func GetCommonSecondOctets() []int {
|
|||||||
const (
|
const (
|
||||||
// 端口和主机限制
|
// 端口和主机限制
|
||||||
SimpleMaxHosts = 10000
|
SimpleMaxHosts = 10000
|
||||||
SimpleMaxPortRange = 5000
|
|
||||||
|
|
||||||
// 网段简写展开
|
// 网段简写展开
|
||||||
DefaultGatewayLastOctet = 1
|
DefaultGatewayLastOctet = 1
|
||||||
|
@ -43,7 +43,7 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string {
|
|||||||
|
|
||||||
// 初始化端口扫描进度条
|
// 初始化端口扫描进度条
|
||||||
if totalTasks > 0 && common.ShowProgress {
|
if totalTasks > 0 && common.ShowProgress {
|
||||||
description := i18n.GetText("progress_port_scanning")
|
description := i18n.GetText("progress_port_scanning_with_threads", common.ThreadNum)
|
||||||
common.InitProgressBar(int64(totalTasks), description)
|
common.InitProgressBar(int64(totalTasks), description)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +133,10 @@ func executeScanTask(pluginName string, target common.HostInfo, ch *chan struct{
|
|||||||
*ch <- struct{}{} // 获取并发槽位
|
*ch <- struct{}{} // 获取并发槽位
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
// 开始监控插件任务
|
||||||
|
monitor := common.GetConcurrencyMonitor()
|
||||||
|
monitor.StartPluginTask()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// 捕获并记录任何可能的panic
|
// 捕获并记录任何可能的panic
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -141,6 +145,7 @@ func executeScanTask(pluginName string, target common.HostInfo, ch *chan struct{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 完成任务,释放资源
|
// 完成任务,释放资源
|
||||||
|
monitor.FinishPluginTask()
|
||||||
wg.Done()
|
wg.Done()
|
||||||
<-*ch // 释放并发槽位
|
<-*ch // 释放并发槽位
|
||||||
}()
|
}()
|
||||||
|
@ -116,7 +116,16 @@ func ConcurrentCredentialScan(
|
|||||||
case <-scanCtx.Done():
|
case <-scanCtx.Done():
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
|
// 开始监控连接
|
||||||
|
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||||
|
monitor := common.GetConcurrencyMonitor()
|
||||||
|
monitor.StartConnection("credential", target)
|
||||||
|
|
||||||
result := scanCredentialWithRetry(scanCtx, scanner, info, credential, config)
|
result := scanCredentialWithRetry(scanCtx, scanner, info, credential, config)
|
||||||
|
|
||||||
|
// 完成连接监控
|
||||||
|
monitor.FinishConnection("credential", target)
|
||||||
|
|
||||||
if result != nil && result.Success {
|
if result != nil && result.Success {
|
||||||
select {
|
select {
|
||||||
case resultChan <- result:
|
case resultChan <- result:
|
||||||
|
Loading…
Reference in New Issue
Block a user