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

主要修复: 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检测只对指定端口进行协议检测 - 时间显示正确
221 lines
6.2 KiB
Go
221 lines
6.2 KiB
Go
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
|
||
} |