package Common import ( "fmt" "sync" "time" "github.com/fatih/color" "github.com/shadow1ng/fscan/Common/logging" "github.com/shadow1ng/fscan/Common/parsers" ) // ParsedConfiguration 解析后的完整配置(兼容旧代码) type ParsedConfiguration struct { *parsers.ParsedConfig } // Parser 主解析器 type Parser struct { mu sync.RWMutex fileReader *parsers.FileReader credentialParser *parsers.CredentialParser targetParser *parsers.TargetParser networkParser *parsers.NetworkParser validationParser *parsers.ValidationParser options *parsers.ParserOptions initialized bool } // NewParser 创建新的解析器实例 func NewParser(options *parsers.ParserOptions) *Parser { if options == nil { options = parsers.DefaultParserOptions() } // 创建文件读取器 fileReader := parsers.NewFileReader(nil) // 创建各个子解析器 credentialParser := parsers.NewCredentialParser(fileReader, nil) targetParser := parsers.NewTargetParser(fileReader, nil) networkParser := parsers.NewNetworkParser(nil) validationParser := parsers.NewValidationParser(nil) return &Parser{ fileReader: fileReader, credentialParser: credentialParser, targetParser: targetParser, networkParser: networkParser, validationParser: validationParser, options: options, initialized: true, } } // 全局解析器实例 var globalParser *Parser var initOnce sync.Once // getGlobalParser 获取全局解析器实例 func getGlobalParser() *Parser { initOnce.Do(func() { globalParser = NewParser(nil) }) return globalParser } // Parse 主解析函数 - 保持与原版本兼容的接口 func Parse(Info *HostInfo) error { // 首先应用LogLevel配置到日志系统 applyLogLevel() parser := getGlobalParser() // 构建输入参数 input := &AllInputs{ Credential: &parsers.CredentialInput{ Username: Username, Password: Password, AddUsers: AddUsers, AddPasswords: AddPasswords, HashValue: HashValue, SshKeyPath: SshKeyPath, Domain: Domain, UsersFile: UsersFile, PasswordsFile: PasswordsFile, HashFile: HashFile, }, Target: &parsers.TargetInput{ Host: Info.Host, HostsFile: HostsFile, ExcludeHosts: ExcludeHosts, Ports: Ports, PortsFile: PortsFile, AddPorts: AddPorts, ExcludePorts: ExcludePorts, TargetURL: TargetURL, URLsFile: URLsFile, HostPort: HostPort, LocalMode: LocalMode, }, Network: &parsers.NetworkInput{ HttpProxy: HttpProxy, Socks5Proxy: Socks5Proxy, Timeout: Timeout, WebTimeout: WebTimeout, DisablePing: DisablePing, DnsLog: DnsLog, UserAgent: UserAgent, Cookie: Cookie, }, } // 执行解析 result, err := parser.ParseAll(input) if err != nil { return fmt.Errorf("解析配置失败: %v", err) } // 更新全局变量以保持兼容性 if err := updateGlobalVariables(result.Config, Info); err != nil { return fmt.Errorf("更新全局变量失败: %v", err) } // 报告警告 for _, warning := range result.Warnings { LogBase(warning) } // 显示解析结果摘要 showParseSummary(result.Config) return nil } // AllInputs 所有输入参数的集合 type AllInputs struct { Credential *parsers.CredentialInput `json:"credential"` Target *parsers.TargetInput `json:"target"` Network *parsers.NetworkInput `json:"network"` } // ParseAll 解析所有配置 func (p *Parser) ParseAll(input *AllInputs) (*parsers.ParseResult, error) { if input == nil { return nil, fmt.Errorf("输入参数为空") } p.mu.Lock() defer p.mu.Unlock() if !p.initialized { return nil, fmt.Errorf("解析器未初始化") } startTime := time.Now() result := &parsers.ParseResult{ Config: &parsers.ParsedConfig{}, Success: true, } var allErrors []error var allWarnings []string // 解析凭据配置 if input.Credential != nil { credResult, err := p.credentialParser.Parse(input.Credential, p.options) if err != nil { allErrors = append(allErrors, fmt.Errorf("凭据解析失败: %v", err)) } else { result.Config.Credentials = credResult.Config.Credentials allErrors = append(allErrors, credResult.Errors...) allWarnings = append(allWarnings, credResult.Warnings...) } } // 解析目标配置 if input.Target != nil { targetResult, err := p.targetParser.Parse(input.Target, p.options) if err != nil { allErrors = append(allErrors, fmt.Errorf("目标解析失败: %v", err)) } else { result.Config.Targets = targetResult.Config.Targets allErrors = append(allErrors, targetResult.Errors...) allWarnings = append(allWarnings, targetResult.Warnings...) } } // 解析网络配置 if input.Network != nil { networkResult, err := p.networkParser.Parse(input.Network, p.options) if err != nil { allErrors = append(allErrors, fmt.Errorf("网络解析失败: %v", err)) } else { result.Config.Network = networkResult.Config.Network allErrors = append(allErrors, networkResult.Errors...) allWarnings = append(allWarnings, networkResult.Warnings...) } } // 执行验证 validationInput := &parsers.ValidationInput{ ScanMode: ScanMode, LocalMode: LocalMode, HasHosts: input.Target != nil && (input.Target.Host != "" || input.Target.HostsFile != ""), HasURLs: input.Target != nil && (input.Target.TargetURL != "" || input.Target.URLsFile != ""), HasPorts: input.Target != nil && (input.Target.Ports != "" || input.Target.PortsFile != ""), HasProxy: input.Network != nil && (input.Network.HttpProxy != "" || input.Network.Socks5Proxy != ""), DisablePing: input.Network != nil && input.Network.DisablePing, HasCredentials: input.Credential != nil && (input.Credential.Username != "" || input.Credential.UsersFile != ""), } validationResult, err := p.validationParser.Parse(validationInput, result.Config, p.options) if err != nil { allErrors = append(allErrors, fmt.Errorf("验证失败: %v", err)) } else { result.Config.Validation = validationResult.Config.Validation allErrors = append(allErrors, validationResult.Errors...) allWarnings = append(allWarnings, validationResult.Warnings...) } // 汇总结果 result.Errors = allErrors result.Warnings = allWarnings result.ParseTime = time.Since(startTime) result.Success = len(allErrors) == 0 return result, nil } // updateGlobalVariables 更新全局变量以保持向后兼容性 func updateGlobalVariables(config *parsers.ParsedConfig, info *HostInfo) error { if config == nil { return nil } // 更新凭据相关全局变量 if config.Credentials != nil { if len(config.Credentials.Usernames) > 0 { // 更新全局用户字典 for serviceName := range Userdict { Userdict[serviceName] = config.Credentials.Usernames } } if len(config.Credentials.Passwords) > 0 { Passwords = config.Credentials.Passwords } if len(config.Credentials.HashValues) > 0 { HashValues = config.Credentials.HashValues } if len(config.Credentials.HashBytes) > 0 { HashBytes = config.Credentials.HashBytes } } // 更新目标相关全局变量 if config.Targets != nil { if len(config.Targets.Hosts) > 0 { if info.Host == "" { info.Host = joinStrings(config.Targets.Hosts, ",") } else { info.Host += "," + joinStrings(config.Targets.Hosts, ",") } } if len(config.Targets.URLs) > 0 { URLs = config.Targets.URLs } if len(config.Targets.Ports) > 0 { Ports = joinInts(config.Targets.Ports, ",") } if len(config.Targets.ExcludePorts) > 0 { ExcludePorts = joinInts(config.Targets.ExcludePorts, ",") } if len(config.Targets.HostPorts) > 0 { HostPort = config.Targets.HostPorts } } // 更新网络相关全局变量 if config.Network != nil { if config.Network.HttpProxy != "" { HttpProxy = config.Network.HttpProxy } if config.Network.Socks5Proxy != "" { Socks5Proxy = config.Network.Socks5Proxy } if config.Network.Timeout > 0 { Timeout = int64(config.Network.Timeout.Seconds()) } if config.Network.WebTimeout > 0 { WebTimeout = int64(config.Network.WebTimeout.Seconds()) } if config.Network.UserAgent != "" { UserAgent = config.Network.UserAgent } if config.Network.Cookie != "" { Cookie = config.Network.Cookie } DisablePing = config.Network.DisablePing DnsLog = config.Network.EnableDNSLog } return nil } // 保持原有的独立解析函数以确保向后兼容性 // ParseUser 解析用户名配置 - 兼容接口 func ParseUser() error { parser := getGlobalParser() input := &parsers.CredentialInput{ Username: Username, UsersFile: UsersFile, AddUsers: AddUsers, } result, err := parser.credentialParser.Parse(input, parser.options) if err != nil { return err } // 更新全局变量 if len(result.Config.Credentials.Usernames) > 0 { for serviceName := range Userdict { Userdict[serviceName] = result.Config.Credentials.Usernames } } return nil } // ParsePass 解析密码配置 - 兼容接口 func ParsePass(Info *HostInfo) error { parser := getGlobalParser() // 处理密码 credInput := &parsers.CredentialInput{ Password: Password, PasswordsFile: PasswordsFile, AddPasswords: AddPasswords, HashValue: HashValue, HashFile: HashFile, } credResult, err := parser.credentialParser.Parse(credInput, parser.options) if err != nil { LogError(fmt.Sprintf("密码解析失败: %v", err)) } else if credResult.Config.Credentials != nil { if len(credResult.Config.Credentials.Passwords) > 0 { Passwords = credResult.Config.Credentials.Passwords } if len(credResult.Config.Credentials.HashValues) > 0 { HashValues = credResult.Config.Credentials.HashValues } if len(credResult.Config.Credentials.HashBytes) > 0 { HashBytes = credResult.Config.Credentials.HashBytes } } // 处理URL和主机 targetInput := &parsers.TargetInput{ TargetURL: TargetURL, URLsFile: URLsFile, Host: Info.Host, HostsFile: HostsFile, Ports: Ports, PortsFile: PortsFile, AddPorts: AddPorts, ExcludePorts: ExcludePorts, } targetResult, err := parser.targetParser.Parse(targetInput, parser.options) if err != nil { LogError(fmt.Sprintf("目标解析失败: %v", err)) } else if targetResult.Config.Targets != nil { if len(targetResult.Config.Targets.URLs) > 0 { URLs = targetResult.Config.Targets.URLs } if len(targetResult.Config.Targets.Hosts) > 0 { Info.Host = joinStrings(targetResult.Config.Targets.Hosts, ",") } if len(targetResult.Config.Targets.Ports) > 0 { Ports = joinInts(targetResult.Config.Targets.Ports, ",") } } return nil } // ParseInput 解析输入参数 - 兼容接口 func ParseInput(Info *HostInfo) error { parser := getGlobalParser() // 网络配置解析 networkInput := &parsers.NetworkInput{ HttpProxy: HttpProxy, Socks5Proxy: Socks5Proxy, Timeout: Timeout, WebTimeout: WebTimeout, DisablePing: DisablePing, DnsLog: DnsLog, UserAgent: UserAgent, Cookie: Cookie, } networkResult, err := parser.networkParser.Parse(networkInput, parser.options) if err != nil { return fmt.Errorf("网络配置解析失败: %v", err) } // 更新全局变量 if networkResult.Config.Network != nil { HttpProxy = networkResult.Config.Network.HttpProxy Socks5Proxy = networkResult.Config.Network.Socks5Proxy if networkResult.Config.Network.Timeout > 0 { Timeout = int64(networkResult.Config.Network.Timeout.Seconds()) } if networkResult.Config.Network.WebTimeout > 0 { WebTimeout = int64(networkResult.Config.Network.WebTimeout.Seconds()) } UserAgent = networkResult.Config.Network.UserAgent Cookie = networkResult.Config.Network.Cookie DisablePing = networkResult.Config.Network.DisablePing DnsLog = networkResult.Config.Network.EnableDNSLog } // 验证配置 validationInput := &parsers.ValidationInput{ ScanMode: ScanMode, LocalMode: LocalMode, HasHosts: Info.Host != "" || HostsFile != "", HasURLs: TargetURL != "" || URLsFile != "", HasPorts: Ports != "" || PortsFile != "", HasProxy: HttpProxy != "" || Socks5Proxy != "", DisablePing: DisablePing, } validationResult, err := parser.validationParser.Parse(validationInput, nil, parser.options) if err != nil { return fmt.Errorf("参数验证失败: %v", err) } // 报告验证警告 for _, warning := range validationResult.Warnings { LogBase(warning) } // 如果有严重错误,返回错误 for _, validationError := range validationResult.Errors { LogError(validationError.Error()) } return nil } // 保持原有的工具函数 // ReadFileLines 读取文件行 - 兼容接口 func ReadFileLines(filename string) ([]string, error) { parser := getGlobalParser() result, err := parser.fileReader.ReadFile(filename) if err != nil { return nil, err } return result.Lines, nil } // RemoveDuplicate 去重函数 - 保持原有实现 func RemoveDuplicate(old []string) []string { temp := make(map[string]struct{}) var result []string for _, item := range old { if _, exists := temp[item]; !exists { temp[item] = struct{}{} result = append(result, item) } } return result } // 辅助函数 // joinStrings 连接字符串切片 func joinStrings(slice []string, sep string) string { if len(slice) == 0 { return "" } result := slice[0] for i := 1; i < len(slice); i++ { result += sep + slice[i] } return result } // joinInts 连接整数切片 func joinInts(slice []int, sep string) string { if len(slice) == 0 { return "" } result := fmt.Sprintf("%d", slice[0]) for i := 1; i < len(slice); i++ { result += sep + fmt.Sprintf("%d", slice[i]) } return result } // GetParser 获取解析器实例 - 新增API func GetParser() *Parser { return getGlobalParser() } // SetParserOptions 设置解析器选项 - 新增API func SetParserOptions(options *parsers.ParserOptions) { globalParser = NewParser(options) } // ClearParserCache 清空解析器缓存 - 新增API func ClearParserCache() { if globalParser != nil && globalParser.fileReader != nil { globalParser.fileReader.ClearCache() } } // showParseSummary 显示解析结果摘要 func showParseSummary(config *parsers.ParsedConfig) { if config == nil { return } // 显示目标信息 if config.Targets != nil { if len(config.Targets.Hosts) > 0 { if len(config.Targets.Hosts) <= 5 { LogBase(fmt.Sprintf("目标主机: %s", joinStrings(config.Targets.Hosts, ", "))) } else { LogBase(fmt.Sprintf("目标主机: %s ... (共%d个)", joinStrings(config.Targets.Hosts[:5], ", "), len(config.Targets.Hosts))) } } if len(config.Targets.URLs) > 0 { if len(config.Targets.URLs) <= 3 { LogBase(fmt.Sprintf("目标URL: %s", joinStrings(config.Targets.URLs, ", "))) } else { LogBase(fmt.Sprintf("目标URL: %s ... (共%d个)", joinStrings(config.Targets.URLs[:3], ", "), len(config.Targets.URLs))) } } if len(config.Targets.Ports) > 0 { if len(config.Targets.Ports) <= 20 { LogBase(fmt.Sprintf("扫描端口: %s", joinInts(config.Targets.Ports, ", "))) } else { LogBase(fmt.Sprintf("扫描端口: %s ... (共%d个)", joinInts(config.Targets.Ports[:20], ", "), len(config.Targets.Ports))) } } if len(config.Targets.ExcludePorts) > 0 { LogBase(fmt.Sprintf("排除端口: %s", joinInts(config.Targets.ExcludePorts, ", "))) } if config.Targets.LocalMode { LogBase("本地扫描模式") } } // 显示网络配置 if config.Network != nil { if config.Network.HttpProxy != "" { LogBase(fmt.Sprintf("HTTP代理: %s", config.Network.HttpProxy)) } if config.Network.Socks5Proxy != "" { LogBase(fmt.Sprintf("Socks5代理: %s", config.Network.Socks5Proxy)) } if config.Network.Timeout > 0 { LogBase(fmt.Sprintf("连接超时: %v", config.Network.Timeout)) } if config.Network.WebTimeout > 0 { LogBase(fmt.Sprintf("Web超时: %v", config.Network.WebTimeout)) } } // 显示凭据信息 if config.Credentials != nil { if len(config.Credentials.Usernames) > 0 { LogBase(fmt.Sprintf("用户名数量: %d", len(config.Credentials.Usernames))) } if len(config.Credentials.Passwords) > 0 { LogBase(fmt.Sprintf("密码数量: %d", len(config.Credentials.Passwords))) } if len(config.Credentials.HashValues) > 0 { LogBase(fmt.Sprintf("Hash数量: %d", len(config.Credentials.HashValues))) } } } // applyLogLevel 应用LogLevel配置到日志系统 func applyLogLevel() { if LogLevel == "" { return // 使用默认级别 } // 根据LogLevel字符串获取对应的日志级别 var level logging.LogLevel switch LogLevel { case LogLevelAll: level = logging.LevelAll case LogLevelError: level = logging.LevelError case LogLevelBase: level = logging.LevelBase case LogLevelInfo: level = logging.LevelInfo case LogLevelSuccess: level = logging.LevelSuccess case LogLevelDebug: level = logging.LevelDebug case LogLevelInfoSuccess: level = logging.LevelInfoSuccess case LogLevelBaseInfoSuccess: level = logging.LevelBaseInfoSuccess default: // 向后兼容:如果是老的字符串格式 switch LogLevel { case "ALL": level = logging.LevelAll case "ERROR": level = logging.LevelError case "BASE": level = logging.LevelBase case "INFO": level = logging.LevelInfo case "SUCCESS": level = logging.LevelSuccess case "DEBUG": level = logging.LevelDebug case "debug": level = logging.LevelAll // 兼容旧的debug行为 default: return // 无效的级别,保持默认 } } // 更新全局日志管理器的级别 if globalLogger != nil { config := &logging.LoggerConfig{ Level: level, EnableColor: !NoColor, SlowOutput: SlowLogOutput, ShowProgress: true, StartTime: StartTime, LevelColors: map[logging.LogLevel]color.Attribute{ logging.LevelError: color.FgBlue, logging.LevelBase: color.FgYellow, logging.LevelInfo: color.FgGreen, logging.LevelSuccess: color.FgRed, logging.LevelDebug: color.FgWhite, }, } newLogger := logging.NewLogger(config) if ProgressBar != nil { newLogger.SetProgressBar(ProgressBar) } newLogger.SetOutputMutex(&OutputMutex) // 更新全局日志管理器 globalLogger = newLogger status = newLogger.GetScanStatus() } }