diff --git a/Common/ConcurrencyMonitor.go b/Common/ConcurrencyMonitor.go new file mode 100644 index 0000000..539655c --- /dev/null +++ b/Common/ConcurrencyMonitor.go @@ -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 +} \ No newline at end of file diff --git a/Common/Flag.go b/Common/Flag.go index b99c6cb..393b8f5 100644 --- a/Common/Flag.go +++ b/Common/Flag.go @@ -142,7 +142,7 @@ func Flag(Info *HostInfo) { flag.StringVar(&ScanMode, "m", "all", i18n.GetText("flag_scan_mode")) flag.IntVar(&ThreadNum, "t", 600, i18n.GetText("flag_thread_num")) 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")) // LiveTop 参数已移除,改为智能控制 flag.BoolVar(&DisablePing, "np", false, i18n.GetText("flag_disable_ping")) diff --git a/Common/Parse.go b/Common/Parse.go index 96646ff..6e2c4b7 100644 --- a/Common/Parse.go +++ b/Common/Parse.go @@ -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.HttpProxy != "" { @@ -400,9 +406,6 @@ func showParseSummary(config *parsers.ParsedConfig) { if 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 { LogBase(i18n.GetText("network_web_timeout", config.Network.WebTimeout)) } diff --git a/Common/ProgressManager.go b/Common/ProgressManager.go index 617cc70..66b6bbf 100644 --- a/Common/ProgressManager.go +++ b/Common/ProgressManager.go @@ -146,6 +146,9 @@ func (pm *ProgressManager) generateProgressBar() string { percentage := float64(pm.current) / float64(pm.total) * 100 elapsed := time.Since(pm.startTime) + // 获取并发状态 + concurrencyStatus := GetConcurrencyMonitor().GetConcurrencyStatus() + // 计算预估剩余时间 var eta string if pm.current > 0 { @@ -194,8 +197,16 @@ func (pm *ProgressManager) generateProgressBar() string { 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) + + // 添加并发状态 + if concurrencyStatus != "" { + return fmt.Sprintf("%s [%s]", baseProgress, concurrencyStatus) + } + + return baseProgress } // showCompletionInfo 显示完成信息 diff --git a/Common/i18n/messages/scan.go b/Common/i18n/messages/scan.go index 2c432aa..b568552 100644 --- a/Common/i18n/messages/scan.go +++ b/Common/i18n/messages/scan.go @@ -224,6 +224,10 @@ var ScanMessages = map[string]map[string]string{ LangZH: "端口扫描", LangEN: "Port Scanning", }, + "progress_port_scanning_with_threads": { + LangZH: "端口扫描 (线程:%d)", + LangEN: "Port Scanning (Threads:%d)", + }, "progress_scan_completed": { LangZH: "扫描完成:", LangEN: "Scan Completed:", @@ -236,4 +240,44 @@ var ScanMessages = map[string]map[string]string{ LangZH: "开放端口", 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", + }, } \ No newline at end of file diff --git a/Common/parsers/Simple.go b/Common/parsers/Simple.go index 066b5d7..8bc456b 100644 --- a/Common/parsers/Simple.go +++ b/Common/parsers/Simple.go @@ -290,11 +290,6 @@ func parsePortRange(rangeStr string) []int { var ports []int for i := start; i <= end; i++ { ports = append(ports, i) - - // 限制端口范围大小 - if len(ports) > SimpleMaxPortRange { - break - } } return ports diff --git a/Common/parsers/constants.go b/Common/parsers/constants.go index 5d2e590..26d92e7 100644 --- a/Common/parsers/constants.go +++ b/Common/parsers/constants.go @@ -184,7 +184,6 @@ func GetCommonSecondOctets() []int { const ( // 端口和主机限制 SimpleMaxHosts = 10000 - SimpleMaxPortRange = 5000 // 网段简写展开 DefaultGatewayLastOctet = 1 diff --git a/Core/PortScan.go b/Core/PortScan.go index bfde0ca..ab82904 100644 --- a/Core/PortScan.go +++ b/Core/PortScan.go @@ -43,7 +43,7 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string { // 初始化端口扫描进度条 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) } diff --git a/Core/Scanner.go b/Core/Scanner.go index 8b8abcb..d787d5b 100644 --- a/Core/Scanner.go +++ b/Core/Scanner.go @@ -133,6 +133,10 @@ func executeScanTask(pluginName string, target common.HostInfo, ch *chan struct{ *ch <- struct{}{} // 获取并发槽位 go func() { + // 开始监控插件任务 + monitor := common.GetConcurrencyMonitor() + monitor.StartPluginTask() + defer func() { // 捕获并记录任何可能的panic if r := recover(); r != nil { @@ -141,6 +145,7 @@ func executeScanTask(pluginName string, target common.HostInfo, ch *chan struct{ } // 完成任务,释放资源 + monitor.FinishPluginTask() wg.Done() <-*ch // 释放并发槽位 }() diff --git a/Plugins/base/scanner.go b/Plugins/base/scanner.go index 5187402..39e707a 100644 --- a/Plugins/base/scanner.go +++ b/Plugins/base/scanner.go @@ -116,7 +116,16 @@ func ConcurrentCredentialScan( case <-scanCtx.Done(): return default: + // 开始监控连接 + target := fmt.Sprintf("%s:%s", info.Host, info.Ports) + monitor := common.GetConcurrencyMonitor() + monitor.StartConnection("credential", target) + result := scanCredentialWithRetry(scanCtx, scanner, info, credential, config) + + // 完成连接监控 + monitor.FinishConnection("credential", target) + if result != nil && result.Success { select { case resultChan <- result: