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

- 将Config相关文件重构为独立的config模块 - 创建config/Types.go定义核心配置数据结构 - 新增config/ServiceDict.go管理服务认证字典(线程安全) - 新增config/PortMapping.go管理端口探测器映射(线程安全) - 新增config/ScanOptions.go提供扫描选项管理(线程安全) - 新增config/Manager.go统一配置管理器 - 新增Variables.go作为向后兼容桥接层 - 重构Config.go为兼容入口点,委托给新模块 - 删除原有的单体配置文件 - 修复用户字典和密码字典初始化问题 - 保持完全向后兼容性,现有API无需修改 - 提升代码组织性和可维护性
433 lines
12 KiB
Go
433 lines
12 KiB
Go
package config
|
||
|
||
import (
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
// ScanOptionsManager 扫描选项管理器
|
||
type ScanOptionsManager struct {
|
||
mu sync.RWMutex
|
||
options *Config
|
||
}
|
||
|
||
// NewScanOptionsManager 创建扫描选项管理器
|
||
func NewScanOptionsManager() *ScanOptionsManager {
|
||
return &ScanOptionsManager{
|
||
options: NewConfig(),
|
||
}
|
||
}
|
||
|
||
// GetConfig 获取完整配置
|
||
func (som *ScanOptionsManager) GetConfig() *Config {
|
||
som.mu.RLock()
|
||
defer som.mu.RUnlock()
|
||
|
||
// 返回深拷贝,避免外部修改
|
||
return som.copyConfig(som.options)
|
||
}
|
||
|
||
// SetConfig 设置完整配置
|
||
func (som *ScanOptionsManager) SetConfig(config *Config) {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
if config != nil {
|
||
som.options = som.copyConfig(config)
|
||
som.options.LastUpdated = time.Now()
|
||
}
|
||
}
|
||
|
||
// UpdateScanTarget 更新扫描目标配置
|
||
func (som *ScanOptionsManager) UpdateScanTarget(target *ScanTargetConfig) {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
if target != nil {
|
||
som.options.ScanTarget = target
|
||
som.options.LastUpdated = time.Now()
|
||
}
|
||
}
|
||
|
||
// UpdateCredential 更新认证配置
|
||
func (som *ScanOptionsManager) UpdateCredential(credential *CredentialConfig) {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
if credential != nil {
|
||
som.options.Credential = credential
|
||
som.options.LastUpdated = time.Now()
|
||
}
|
||
}
|
||
|
||
// UpdateScanControl 更新扫描控制配置
|
||
func (som *ScanOptionsManager) UpdateScanControl(control *ScanControlConfig) {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
if control != nil {
|
||
som.options.ScanControl = control
|
||
som.options.LastUpdated = time.Now()
|
||
}
|
||
}
|
||
|
||
// UpdateWebScan 更新Web扫描配置
|
||
func (som *ScanOptionsManager) UpdateWebScan(webScan *WebScanConfig) {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
if webScan != nil {
|
||
som.options.WebScan = webScan
|
||
som.options.LastUpdated = time.Now()
|
||
}
|
||
}
|
||
|
||
// UpdateDisplay 更新显示配置
|
||
func (som *ScanOptionsManager) UpdateDisplay(display *DisplayConfig) {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
if display != nil {
|
||
som.options.Display = display
|
||
som.options.LastUpdated = time.Now()
|
||
}
|
||
}
|
||
|
||
// UpdateOutput 更新输出配置
|
||
func (som *ScanOptionsManager) UpdateOutput(output *OutputConfig) {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
if output != nil {
|
||
som.options.Output = output
|
||
som.options.LastUpdated = time.Now()
|
||
}
|
||
}
|
||
|
||
// SetDefaults 设置默认值
|
||
func (som *ScanOptionsManager) SetDefaults() {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
// 设置扫描控制默认值
|
||
if som.options.ScanControl.ThreadNum <= 0 {
|
||
som.options.ScanControl.ThreadNum = 600
|
||
}
|
||
if som.options.ScanControl.ModuleThreadNum <= 0 {
|
||
som.options.ScanControl.ModuleThreadNum = 10
|
||
}
|
||
if som.options.ScanControl.Timeout <= 0 {
|
||
som.options.ScanControl.Timeout = 3
|
||
}
|
||
if som.options.ScanControl.GlobalTimeout <= 0 {
|
||
som.options.ScanControl.GlobalTimeout = 300 // 5分钟
|
||
}
|
||
|
||
// 设置Web扫描默认值
|
||
if som.options.WebScan.WebTimeout <= 0 {
|
||
som.options.WebScan.WebTimeout = 5
|
||
}
|
||
|
||
// 设置暴力破解默认值
|
||
if som.options.BruteForce.MaxRetries <= 0 {
|
||
som.options.BruteForce.MaxRetries = 3
|
||
}
|
||
|
||
// 设置显示默认值
|
||
if som.options.Display.LogLevel == "" {
|
||
som.options.Display.LogLevel = "SUCCESS"
|
||
}
|
||
if som.options.Display.Language == "" {
|
||
som.options.Display.Language = "zh"
|
||
}
|
||
|
||
// 设置输出默认值
|
||
if som.options.Output.OutputFormat == "" {
|
||
som.options.Output.OutputFormat = "txt"
|
||
}
|
||
if som.options.Output.Outputfile == "" {
|
||
som.options.Output.Outputfile = "result.txt"
|
||
}
|
||
|
||
// 设置网络默认值
|
||
if som.options.Network.UserAgent == "" {
|
||
som.options.Network.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
|
||
}
|
||
if som.options.Network.Accept == "" {
|
||
som.options.Network.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
|
||
}
|
||
if som.options.Network.PocNum <= 0 {
|
||
som.options.Network.PocNum = 20
|
||
}
|
||
|
||
som.options.LastUpdated = time.Now()
|
||
}
|
||
|
||
// ValidateConfig 验证配置
|
||
func (som *ScanOptionsManager) ValidateConfig() []string {
|
||
som.mu.RLock()
|
||
defer som.mu.RUnlock()
|
||
|
||
var warnings []string
|
||
|
||
// 验证线程数配置
|
||
if som.options.ScanControl.ThreadNum > 1000 {
|
||
warnings = append(warnings, "线程数过大,可能影响系统性能")
|
||
}
|
||
|
||
// 验证超时配置
|
||
if som.options.ScanControl.Timeout > som.options.WebScan.WebTimeout {
|
||
warnings = append(warnings, "Web超时时间大于普通超时时间,可能导致不期望的行为")
|
||
}
|
||
|
||
// 验证超时配置合理性
|
||
if som.options.ScanControl.Timeout < 1 {
|
||
warnings = append(warnings, "超时时间过短,可能导致误报")
|
||
}
|
||
|
||
if som.options.WebScan.WebTimeout < 1 {
|
||
warnings = append(warnings, "Web超时时间过短,可能导致误报")
|
||
}
|
||
|
||
// 验证全局超时
|
||
if som.options.ScanControl.GlobalTimeout < 60 {
|
||
warnings = append(warnings, "全局超时时间过短,扫描可能提前终止")
|
||
}
|
||
|
||
return warnings
|
||
}
|
||
|
||
// GetSummary 获取配置摘要
|
||
func (som *ScanOptionsManager) GetSummary() map[string]interface{} {
|
||
som.mu.RLock()
|
||
defer som.mu.RUnlock()
|
||
|
||
return map[string]interface{}{
|
||
"scan_mode": som.options.ScanControl.ScanMode,
|
||
"thread_num": som.options.ScanControl.ThreadNum,
|
||
"timeout": som.options.ScanControl.Timeout,
|
||
"web_timeout": som.options.WebScan.WebTimeout,
|
||
"disable_ping": som.options.ScanControl.DisablePing,
|
||
"local_mode": som.options.ScanControl.LocalMode,
|
||
"log_level": som.options.Display.LogLevel,
|
||
"output_format": som.options.Output.OutputFormat,
|
||
"has_proxy": som.options.WebScan.HttpProxy != "" || som.options.WebScan.Socks5Proxy != "",
|
||
"has_credentials": som.options.Credential.Username != "" || som.options.InputFile.UsersFile != "",
|
||
"last_updated": som.options.LastUpdated,
|
||
}
|
||
}
|
||
|
||
// ResetToDefaults 重置为默认配置
|
||
func (som *ScanOptionsManager) ResetToDefaults() {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
som.options = NewConfig()
|
||
som.SetDefaults()
|
||
}
|
||
|
||
// ClearConfig 清空配置
|
||
func (som *ScanOptionsManager) ClearConfig() {
|
||
som.mu.Lock()
|
||
defer som.mu.Unlock()
|
||
|
||
// 清空所有配置项但保持结构
|
||
som.options.ScanTarget.Ports = ""
|
||
som.options.ScanTarget.ExcludePorts = ""
|
||
som.options.ScanTarget.ExcludeHosts = ""
|
||
som.options.ScanTarget.AddPorts = ""
|
||
som.options.ScanTarget.HostPort = nil
|
||
|
||
som.options.Credential.Username = ""
|
||
som.options.Credential.Password = ""
|
||
som.options.Credential.AddUsers = ""
|
||
som.options.Credential.AddPasswords = ""
|
||
som.options.Credential.Domain = ""
|
||
som.options.Credential.HashValue = ""
|
||
som.options.Credential.HashValues = nil
|
||
som.options.Credential.HashBytes = nil
|
||
som.options.Credential.HashFile = ""
|
||
som.options.Credential.SshKeyPath = ""
|
||
|
||
som.options.InputFile.HostsFile = ""
|
||
som.options.InputFile.UsersFile = ""
|
||
som.options.InputFile.PasswordsFile = ""
|
||
som.options.InputFile.PortsFile = ""
|
||
|
||
som.options.WebScan.TargetURL = ""
|
||
som.options.WebScan.URLsFile = ""
|
||
som.options.WebScan.URLs = nil
|
||
som.options.WebScan.HttpProxy = ""
|
||
som.options.WebScan.Socks5Proxy = ""
|
||
|
||
som.options.LastUpdated = time.Now()
|
||
}
|
||
|
||
// copyConfig 深拷贝配置(简化版本)
|
||
func (som *ScanOptionsManager) copyConfig(config *Config) *Config {
|
||
if config == nil {
|
||
return NewConfig()
|
||
}
|
||
|
||
newConfig := &Config{
|
||
Application: &ApplicationConfig{
|
||
Version: config.Application.Version,
|
||
ProgressBar: config.Application.ProgressBar, // 指针共享
|
||
},
|
||
ScanTarget: &ScanTargetConfig{
|
||
Ports: config.ScanTarget.Ports,
|
||
ExcludePorts: config.ScanTarget.ExcludePorts,
|
||
ExcludeHosts: config.ScanTarget.ExcludeHosts,
|
||
AddPorts: config.ScanTarget.AddPorts,
|
||
},
|
||
Credential: &CredentialConfig{
|
||
Username: config.Credential.Username,
|
||
Password: config.Credential.Password,
|
||
AddUsers: config.Credential.AddUsers,
|
||
AddPasswords: config.Credential.AddPasswords,
|
||
Domain: config.Credential.Domain,
|
||
HashValue: config.Credential.HashValue,
|
||
HashFile: config.Credential.HashFile,
|
||
SshKeyPath: config.Credential.SshKeyPath,
|
||
},
|
||
ScanControl: &ScanControlConfig{
|
||
ScanMode: config.ScanControl.ScanMode,
|
||
ThreadNum: config.ScanControl.ThreadNum,
|
||
ModuleThreadNum: config.ScanControl.ModuleThreadNum,
|
||
Timeout: config.ScanControl.Timeout,
|
||
GlobalTimeout: config.ScanControl.GlobalTimeout,
|
||
LiveTop: config.ScanControl.LiveTop,
|
||
DisablePing: config.ScanControl.DisablePing,
|
||
UsePing: config.ScanControl.UsePing,
|
||
EnableFingerprint: config.ScanControl.EnableFingerprint,
|
||
LocalMode: config.ScanControl.LocalMode,
|
||
},
|
||
InputFile: &InputFileConfig{
|
||
HostsFile: config.InputFile.HostsFile,
|
||
UsersFile: config.InputFile.UsersFile,
|
||
PasswordsFile: config.InputFile.PasswordsFile,
|
||
PortsFile: config.InputFile.PortsFile,
|
||
},
|
||
WebScan: &WebScanConfig{
|
||
TargetURL: config.WebScan.TargetURL,
|
||
URLsFile: config.WebScan.URLsFile,
|
||
WebTimeout: config.WebScan.WebTimeout,
|
||
HttpProxy: config.WebScan.HttpProxy,
|
||
Socks5Proxy: config.WebScan.Socks5Proxy,
|
||
},
|
||
VulnExploit: &VulnExploitConfig{
|
||
PocPath: config.VulnExploit.PocPath,
|
||
PocInfo: config.VulnExploit.PocInfo,
|
||
DisablePocScan: config.VulnExploit.DisablePocScan,
|
||
RedisFile: config.VulnExploit.RedisFile,
|
||
RedisShell: config.VulnExploit.RedisShell,
|
||
DisableRedis: config.VulnExploit.DisableRedis,
|
||
RedisWritePath: config.VulnExploit.RedisWritePath,
|
||
RedisWriteContent: config.VulnExploit.RedisWriteContent,
|
||
RedisWriteFile: config.VulnExploit.RedisWriteFile,
|
||
Shellcode: config.VulnExploit.Shellcode,
|
||
},
|
||
BruteForce: &BruteForceConfig{
|
||
DisableBrute: config.BruteForce.DisableBrute,
|
||
MaxRetries: config.BruteForce.MaxRetries,
|
||
},
|
||
Display: &DisplayConfig{
|
||
DisableSave: config.Display.DisableSave,
|
||
Silent: config.Display.Silent,
|
||
NoColor: config.Display.NoColor,
|
||
LogLevel: config.Display.LogLevel,
|
||
ShowProgress: config.Display.ShowProgress,
|
||
ShowScanPlan: config.Display.ShowScanPlan,
|
||
SlowLogOutput: config.Display.SlowLogOutput,
|
||
Language: config.Display.Language,
|
||
},
|
||
Output: &OutputConfig{
|
||
Outputfile: config.Output.Outputfile,
|
||
OutputFormat: config.Output.OutputFormat,
|
||
},
|
||
Network: &NetworkConfig{
|
||
UserAgent: config.Network.UserAgent,
|
||
Accept: config.Network.Accept,
|
||
DnsLog: config.Network.DnsLog,
|
||
PocNum: config.Network.PocNum,
|
||
PocFull: config.Network.PocFull,
|
||
Cookie: config.Network.Cookie,
|
||
},
|
||
LastUpdated: config.LastUpdated,
|
||
}
|
||
|
||
// 拷贝切片
|
||
if len(config.ScanTarget.HostPort) > 0 {
|
||
newConfig.ScanTarget.HostPort = make([]string, len(config.ScanTarget.HostPort))
|
||
copy(newConfig.ScanTarget.HostPort, config.ScanTarget.HostPort)
|
||
}
|
||
|
||
if len(config.Credential.HashValues) > 0 {
|
||
newConfig.Credential.HashValues = make([]string, len(config.Credential.HashValues))
|
||
copy(newConfig.Credential.HashValues, config.Credential.HashValues)
|
||
}
|
||
|
||
if len(config.Credential.HashBytes) > 0 {
|
||
newConfig.Credential.HashBytes = make([][]byte, len(config.Credential.HashBytes))
|
||
for i, b := range config.Credential.HashBytes {
|
||
if len(b) > 0 {
|
||
newConfig.Credential.HashBytes[i] = make([]byte, len(b))
|
||
copy(newConfig.Credential.HashBytes[i], b)
|
||
}
|
||
}
|
||
}
|
||
|
||
if len(config.WebScan.URLs) > 0 {
|
||
newConfig.WebScan.URLs = make([]string, len(config.WebScan.URLs))
|
||
copy(newConfig.WebScan.URLs, config.WebScan.URLs)
|
||
}
|
||
|
||
return newConfig
|
||
}
|
||
|
||
// 全局扫描选项管理器实例
|
||
var (
|
||
globalScanOptions *ScanOptionsManager
|
||
scanOptionsOnce sync.Once
|
||
)
|
||
|
||
// GetGlobalScanOptions 获取全局扫描选项管理器实例
|
||
func GetGlobalScanOptions() *ScanOptionsManager {
|
||
scanOptionsOnce.Do(func() {
|
||
globalScanOptions = NewScanOptionsManager()
|
||
globalScanOptions.SetDefaults()
|
||
})
|
||
return globalScanOptions
|
||
}
|
||
|
||
// SetGlobalScanOptions 设置全局扫描选项管理器实例
|
||
func SetGlobalScanOptions(manager *ScanOptionsManager) {
|
||
globalScanOptions = manager
|
||
}
|
||
|
||
// 便利函数,直接使用全局实例
|
||
|
||
// GetGlobalConfig 获取全局配置
|
||
func GetGlobalConfig() *Config {
|
||
return GetGlobalScanOptions().GetConfig()
|
||
}
|
||
|
||
// SetGlobalConfig 设置全局配置
|
||
func SetGlobalConfig(config *Config) {
|
||
GetGlobalScanOptions().SetConfig(config)
|
||
}
|
||
|
||
// SetGlobalDefaults 设置全局默认值
|
||
func SetGlobalDefaults() {
|
||
GetGlobalScanOptions().SetDefaults()
|
||
}
|
||
|
||
// ValidateGlobalConfig 验证全局配置
|
||
func ValidateGlobalConfig() []string {
|
||
return GetGlobalScanOptions().ValidateConfig()
|
||
}
|
||
|
||
// GetGlobalSummary 获取全局配置摘要
|
||
func GetGlobalSummary() map[string]interface{} {
|
||
return GetGlobalScanOptions().GetSummary()
|
||
} |