fscan/common/common.go
ZacharyZcR a3177b28a6 fix: 修复插件系统逻辑Bug和架构问题
主要修复:
1. 修复时间显示Bug - StartTime初始化问题
2. 修复Web智能探测错误检测预定义端口而非用户指定端口
3. 修复本地插件被错误调用到端口扫描中的问题
4. 修复host:port格式双重处理导致的多余端口扫描
5. 统一插件过滤逻辑,消除接口不一致性
6. 优化Web检测缓存机制,减少重复HTTP请求

技术改进:
- 重构插件适用性检查逻辑,确保策略过滤器正确工作
- 区分Web检测的自动发现模式和用户指定端口模式
- 在解析阶段正确处理host:port格式,避免与默认端口冲突
- 完善缓存机制,提升性能

测试验证:
- ./fscan -h 127.0.0.1:3306 现在只检测3306端口
- 本地插件不再参与端口扫描
- Web检测只对指定端口进行协议检测
- 时间显示正确
2025-09-01 23:50:32 +00:00

221 lines
6.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package common
/*
common.go - 简化的统一入口
直接导出核心功能移除base包依赖。
*/
import (
"context"
"crypto/tls"
"fmt"
"net"
"sync"
"time"
"github.com/shadow1ng/fscan/common/logging"
"github.com/shadow1ng/fscan/common/output"
"github.com/shadow1ng/fscan/common/proxy"
)
// =============================================================================
// 核心类型导出 - 直接定义不再通过base包
// =============================================================================
// 类型现已直接定义在types.go中
// type HostInfo
// type ScanPlugin
// 插件类型常量现已直接定义在constants.go中
// const PluginTypeWeb, PluginTypeLocal
// 简化的插件管理器 - 移除复杂的base.LegacyPluginManager
var PluginManager = make(map[string]ScanPlugin)
// =============================================================================
// 日志系统简化接口
// =============================================================================
var globalLogger *logging.Logger
var loggerMutex sync.Mutex
func getGlobalLogger() *logging.Logger {
loggerMutex.Lock()
defer loggerMutex.Unlock()
if globalLogger == nil {
level := getLogLevelFromString(LogLevel)
config := &logging.LoggerConfig{
Level: level,
EnableColor: !NoColor,
SlowOutput: false,
ShowProgress: ShowProgress,
StartTime: StartTime,
}
globalLogger = logging.NewLogger(config)
// ProgressBar设置已简化
globalLogger.SetOutputMutex(&OutputMutex)
// 设置协调输出函数使用LogWithProgress
globalLogger.SetCoordinatedOutput(LogWithProgress)
}
return globalLogger
}
func getLogLevelFromString(levelStr string) logging.LogLevel {
switch levelStr {
case "all", "ALL":
return logging.LevelAll
case "error", "ERROR":
return logging.LevelError
case "base", "BASE":
return logging.LevelBase
case "info", "INFO":
return logging.LevelInfo
case "success", "SUCCESS":
return logging.LevelSuccess
case "debug", "DEBUG":
return logging.LevelDebug
case "info,success":
return logging.LevelInfoSuccess
case "base,info,success", "BASE_INFO_SUCCESS":
return logging.LevelBaseInfoSuccess
default:
return logging.LevelInfoSuccess
}
}
// 日志函数
func InitLogger() {
loggerMutex.Lock()
globalLogger = nil
loggerMutex.Unlock()
getGlobalLogger().Initialize()
}
func LogDebug(msg string) { getGlobalLogger().Debug(msg) }
func LogBase(msg string) { getGlobalLogger().Base(msg) }
func LogInfo(msg string) { getGlobalLogger().Info(msg) }
func LogSuccess(result string) { getGlobalLogger().Success(result) }
func LogError(errMsg string) { getGlobalLogger().Error(errMsg) }
// =============================================================================
// 输出系统简化接口
// =============================================================================
var ResultOutput *output.Manager
func InitOutput() error {
if Outputfile == "" {
return fmt.Errorf("output file not specified")
}
var format output.OutputFormat
switch OutputFormat {
case "txt":
format = output.FormatTXT
case "json":
format = output.FormatJSON
case "csv":
format = output.FormatCSV
default:
return fmt.Errorf("invalid output format: %s", OutputFormat)
}
config := output.DefaultManagerConfig(Outputfile, format)
manager, err := output.NewManager(config)
if err != nil {
return err
}
ResultOutput = manager
return nil
}
func CloseOutput() error {
if ResultOutput == nil {
return nil
}
return ResultOutput.Close()
}
func SaveResult(result *output.ScanResult) error {
if ResultOutput == nil {
return fmt.Errorf("output not initialized")
}
return ResultOutput.SaveResult(result)
}
// =============================================================================
// 网络连接辅助函数
// =============================================================================
// WrapperTcpWithTimeout TCP连接包装器带超时
func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout(network, address, timeout)
}
// WrapperTcpWithContext TCP连接包装器带上下文和代理支持
func WrapperTcpWithContext(ctx context.Context, network, address string) (net.Conn, error) {
// 检查是否配置了SOCKS5代理
if Socks5Proxy != "" {
proxyConfig := &proxy.ProxyConfig{
Type: proxy.ProxyTypeSOCKS5,
Address: Socks5Proxy,
Timeout: time.Second * 10,
}
proxyManager := proxy.NewProxyManager(proxyConfig)
dialer, err := proxyManager.GetDialer()
if err != nil {
LogDebug(fmt.Sprintf("SOCKS5代理连接失败回退到直连: %v", err))
// 代理失败时回退到直连
var d net.Dialer
return d.DialContext(ctx, network, address)
}
LogDebug(fmt.Sprintf("使用SOCKS5代理连接: %s -> %s", Socks5Proxy, address))
return dialer.DialContext(ctx, network, address)
}
// 没有配置代理,使用直连
var d net.Dialer
return d.DialContext(ctx, network, address)
}
// WrapperTlsWithContext TLS连接包装器带上下文和代理支持
func WrapperTlsWithContext(ctx context.Context, network, address string, config *tls.Config) (net.Conn, error) {
// 检查是否配置了SOCKS5代理
if Socks5Proxy != "" {
proxyConfig := &proxy.ProxyConfig{
Type: proxy.ProxyTypeSOCKS5,
Address: Socks5Proxy,
Timeout: time.Second * 10,
}
proxyManager := proxy.NewProxyManager(proxyConfig)
tlsDialer, err := proxyManager.GetTLSDialer()
if err != nil {
LogDebug(fmt.Sprintf("SOCKS5代理TLS连接失败回退到直连: %v", err))
// 代理失败时回退到直连
d := &tls.Dialer{Config: config}
return d.DialContext(ctx, network, address)
}
LogDebug(fmt.Sprintf("使用SOCKS5代理TLS连接: %s -> %s", Socks5Proxy, address))
return tlsDialer.DialTLSContext(ctx, network, address, config)
}
// 没有配置代理,使用直连
d := &tls.Dialer{Config: config}
return d.DialContext(ctx, network, address)
}
// =============================================================================
// 错误处理辅助函数
// =============================================================================
// CheckErrs 检查单个错误 - 简化版本
func CheckErrs(err error) error {
return err
}