mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
Compare commits
8 Commits
f943f04de7
...
b38684bc9e
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b38684bc9e | ||
![]() |
78b8ff4f81 | ||
![]() |
022461f407 | ||
![]() |
78f81610cd | ||
![]() |
6c93129cb1 | ||
![]() |
e8a7c594e9 | ||
![]() |
a250fd7e22 | ||
![]() |
647860f170 |
@ -148,6 +148,7 @@ func Flag(Info *HostInfo) {
|
|||||||
flag.BoolVar(&DisablePing, "np", false, i18n.GetText("flag_disable_ping"))
|
flag.BoolVar(&DisablePing, "np", false, i18n.GetText("flag_disable_ping"))
|
||||||
flag.BoolVar(&EnableFingerprint, "fingerprint", false, i18n.GetText("flag_enable_fingerprint"))
|
flag.BoolVar(&EnableFingerprint, "fingerprint", false, i18n.GetText("flag_enable_fingerprint"))
|
||||||
flag.BoolVar(&LocalMode, "local", false, i18n.GetText("flag_local_mode"))
|
flag.BoolVar(&LocalMode, "local", false, i18n.GetText("flag_local_mode"))
|
||||||
|
flag.BoolVar(&AliveOnly, "ao", false, i18n.GetText("flag_alive_only"))
|
||||||
|
|
||||||
// ═════════════════════════════════════════════════
|
// ═════════════════════════════════════════════════
|
||||||
// 认证与凭据参数
|
// 认证与凭据参数
|
||||||
@ -254,6 +255,9 @@ func parseCommandLineArgs() {
|
|||||||
|
|
||||||
// 解析命令行参数
|
// 解析命令行参数
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
// 检查参数冲突
|
||||||
|
checkParameterConflicts()
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseEnvironmentArgs 安全地解析环境变量中的参数
|
// parseEnvironmentArgs 安全地解析环境变量中的参数
|
||||||
@ -337,3 +341,11 @@ func shouldShowHelp(Info *HostInfo) bool {
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkParameterConflicts 检查参数冲突和兼容性
|
||||||
|
func checkParameterConflicts() {
|
||||||
|
// 检查 -ao 和 -m icmp 同时指定的情况(向后兼容提示)
|
||||||
|
if AliveOnly && ScanMode == "icmp" {
|
||||||
|
LogBase(i18n.GetText("param_conflict_ao_icmp_both"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -40,6 +40,7 @@ var (
|
|||||||
Timeout int64 // 直接映射到base.Timeout
|
Timeout int64 // 直接映射到base.Timeout
|
||||||
DisablePing bool // 直接映射到base.DisablePing
|
DisablePing bool // 直接映射到base.DisablePing
|
||||||
LocalMode bool // 直接映射到base.LocalMode
|
LocalMode bool // 直接映射到base.LocalMode
|
||||||
|
AliveOnly bool // 仅存活探测模式
|
||||||
)
|
)
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
45
Common/i18n/init.go
Normal file
45
Common/i18n/init.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package i18n
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n/messages"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
init.go - 国际化模块统一初始化
|
||||||
|
|
||||||
|
自动加载所有分类消息到全局管理器,
|
||||||
|
确保所有消息在程序启动时正确注册。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// init 统一初始化所有国际化消息
|
||||||
|
func init() {
|
||||||
|
// 按类别依次加载所有消息
|
||||||
|
loadAllMessages()
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadAllMessages 加载所有分类的消息
|
||||||
|
func loadAllMessages() {
|
||||||
|
// 加载核心系统消息
|
||||||
|
AddMessages(messages.CoreMessages)
|
||||||
|
|
||||||
|
// 加载解析相关消息
|
||||||
|
AddMessages(messages.ParseMessages)
|
||||||
|
|
||||||
|
// 加载配置相关消息
|
||||||
|
AddMessages(messages.ConfigMessages)
|
||||||
|
|
||||||
|
// 加载扫描相关消息
|
||||||
|
AddMessages(messages.ScanMessages)
|
||||||
|
|
||||||
|
// 加载网络相关消息
|
||||||
|
AddMessages(messages.NetworkMessages)
|
||||||
|
|
||||||
|
// 加载输出相关消息
|
||||||
|
AddMessages(messages.OutputMessages)
|
||||||
|
|
||||||
|
// 加载通用错误消息
|
||||||
|
AddMessages(messages.ErrorMessages)
|
||||||
|
|
||||||
|
// 加载命令行参数消息
|
||||||
|
AddMessages(messages.FlagMessages)
|
||||||
|
}
|
@ -1,911 +0,0 @@
|
|||||||
package i18n
|
|
||||||
|
|
||||||
/*
|
|
||||||
messages.go - 国际化消息定义
|
|
||||||
|
|
||||||
包含项目中所有的国际化消息,按功能模块分类组织,
|
|
||||||
支持中文和英文两种语言。
|
|
||||||
*/
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 核心消息库
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// coreMessages 核心消息映射
|
|
||||||
var coreMessages = map[string]map[string]string{
|
|
||||||
// ========================= 解析错误消息 =========================
|
|
||||||
"parse_error_empty_input": {
|
|
||||||
LangZH: "输入参数为空",
|
|
||||||
LangEN: "Input parameters are empty",
|
|
||||||
},
|
|
||||||
"parse_error_config_failed": {
|
|
||||||
LangZH: "解析配置失败: %v",
|
|
||||||
LangEN: "Failed to parse configuration: %v",
|
|
||||||
},
|
|
||||||
"parse_error_parser_not_init": {
|
|
||||||
LangZH: "解析器未初始化",
|
|
||||||
LangEN: "Parser not initialized",
|
|
||||||
},
|
|
||||||
"parse_error_credential_failed": {
|
|
||||||
LangZH: "凭据解析失败: %v",
|
|
||||||
LangEN: "Failed to parse credentials: %v",
|
|
||||||
},
|
|
||||||
"parse_error_target_failed": {
|
|
||||||
LangZH: "目标解析失败: %v",
|
|
||||||
LangEN: "Failed to parse targets: %v",
|
|
||||||
},
|
|
||||||
"parse_error_network_failed": {
|
|
||||||
LangZH: "网络解析失败: %v",
|
|
||||||
LangEN: "Failed to parse network configuration: %v",
|
|
||||||
},
|
|
||||||
"parse_error_validation_failed": {
|
|
||||||
LangZH: "验证失败: %v",
|
|
||||||
LangEN: "Validation failed: %v",
|
|
||||||
},
|
|
||||||
"parse_error_update_vars_failed": {
|
|
||||||
LangZH: "更新全局变量失败: %v",
|
|
||||||
LangEN: "Failed to update global variables: %v",
|
|
||||||
},
|
|
||||||
"parse_error_target_empty": {
|
|
||||||
LangZH: "目标输入为空",
|
|
||||||
LangEN: "Target input is empty",
|
|
||||||
},
|
|
||||||
"parse_error_credential_empty": {
|
|
||||||
LangZH: "凭据输入为空",
|
|
||||||
LangEN: "Credential input is empty",
|
|
||||||
},
|
|
||||||
"parse_error_network_empty": {
|
|
||||||
LangZH: "网络配置为空",
|
|
||||||
LangEN: "Network configuration is empty",
|
|
||||||
},
|
|
||||||
"parse_error_invalid_ip": {
|
|
||||||
LangZH: "无效的IP地址: %s",
|
|
||||||
LangEN: "Invalid IP address: %s",
|
|
||||||
},
|
|
||||||
"parse_error_invalid_port": {
|
|
||||||
LangZH: "无效的端口: %s",
|
|
||||||
LangEN: "Invalid port: %s",
|
|
||||||
},
|
|
||||||
"parse_error_invalid_url": {
|
|
||||||
LangZH: "无效的URL: %s",
|
|
||||||
LangEN: "Invalid URL: %s",
|
|
||||||
},
|
|
||||||
"parse_error_file_not_found": {
|
|
||||||
LangZH: "文件未找到: %s",
|
|
||||||
LangEN: "File not found: %s",
|
|
||||||
},
|
|
||||||
"parse_error_file_read_failed": {
|
|
||||||
LangZH: "读取文件失败: %s",
|
|
||||||
LangEN: "Failed to read file: %s",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 配置相关消息 =========================
|
|
||||||
"config_sync_start": {
|
|
||||||
LangZH: "开始同步配置",
|
|
||||||
LangEN: "Starting configuration sync",
|
|
||||||
},
|
|
||||||
"config_sync_complete": {
|
|
||||||
LangZH: "配置同步完成",
|
|
||||||
LangEN: "Configuration sync completed",
|
|
||||||
},
|
|
||||||
"config_validation_start": {
|
|
||||||
LangZH: "开始配置验证",
|
|
||||||
LangEN: "Starting configuration validation",
|
|
||||||
},
|
|
||||||
"config_validation_complete": {
|
|
||||||
LangZH: "配置验证完成",
|
|
||||||
LangEN: "Configuration validation completed",
|
|
||||||
},
|
|
||||||
"config_invalid_scan_mode": {
|
|
||||||
LangZH: "无效的扫描模式: %s",
|
|
||||||
LangEN: "Invalid scan mode: %s",
|
|
||||||
},
|
|
||||||
"config_invalid_thread_num": {
|
|
||||||
LangZH: "无效的线程数: %d",
|
|
||||||
LangEN: "Invalid thread number: %d",
|
|
||||||
},
|
|
||||||
"config_invalid_timeout": {
|
|
||||||
LangZH: "无效的超时时间: %v",
|
|
||||||
LangEN: "Invalid timeout: %v",
|
|
||||||
},
|
|
||||||
"config_invalid_proxy": {
|
|
||||||
LangZH: "无效的代理配置: %s",
|
|
||||||
LangEN: "Invalid proxy configuration: %s",
|
|
||||||
},
|
|
||||||
"config_missing_required": {
|
|
||||||
LangZH: "缺少必需的配置项: %s",
|
|
||||||
LangEN: "Missing required configuration: %s",
|
|
||||||
},
|
|
||||||
"config_load_default": {
|
|
||||||
LangZH: "加载默认配置",
|
|
||||||
LangEN: "Loading default configuration",
|
|
||||||
},
|
|
||||||
"config_override_detected": {
|
|
||||||
LangZH: "检测到配置覆盖: %s",
|
|
||||||
LangEN: "Configuration override detected: %s",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 输出系统消息 =========================
|
|
||||||
"output_init_start": {
|
|
||||||
LangZH: "初始化输出系统",
|
|
||||||
LangEN: "Initializing output system",
|
|
||||||
},
|
|
||||||
"output_init_success": {
|
|
||||||
LangZH: "输出系统初始化成功",
|
|
||||||
LangEN: "Output system initialized successfully",
|
|
||||||
},
|
|
||||||
"output_init_failed": {
|
|
||||||
LangZH: "输出系统初始化失败: %v",
|
|
||||||
LangEN: "Failed to initialize output system: %v",
|
|
||||||
},
|
|
||||||
"output_format_invalid": {
|
|
||||||
LangZH: "无效的输出格式: %s",
|
|
||||||
LangEN: "Invalid output format: %s",
|
|
||||||
},
|
|
||||||
"output_path_empty": {
|
|
||||||
LangZH: "输出路径为空",
|
|
||||||
LangEN: "Output path is empty",
|
|
||||||
},
|
|
||||||
"output_not_init": {
|
|
||||||
LangZH: "输出系统未初始化",
|
|
||||||
LangEN: "Output system not initialized",
|
|
||||||
},
|
|
||||||
"output_saving_result": {
|
|
||||||
LangZH: "保存扫描结果: %s -> %s",
|
|
||||||
LangEN: "Saving scan result: %s -> %s",
|
|
||||||
},
|
|
||||||
"output_save_failed": {
|
|
||||||
LangZH: "保存结果失败: %v",
|
|
||||||
LangEN: "Failed to save result: %v",
|
|
||||||
},
|
|
||||||
"output_closing": {
|
|
||||||
LangZH: "关闭输出系统",
|
|
||||||
LangEN: "Closing output system",
|
|
||||||
},
|
|
||||||
"output_closed": {
|
|
||||||
LangZH: "输出系统已关闭",
|
|
||||||
LangEN: "Output system closed",
|
|
||||||
},
|
|
||||||
"output_close_failed": {
|
|
||||||
LangZH: "关闭输出系统失败: %v",
|
|
||||||
LangEN: "Failed to close output system: %v",
|
|
||||||
},
|
|
||||||
"output_config_nil": {
|
|
||||||
LangZH: "配置不能为空",
|
|
||||||
LangEN: "Configuration cannot be nil",
|
|
||||||
},
|
|
||||||
"output_unsupported_format": {
|
|
||||||
LangZH: "不支持的输出格式: %s",
|
|
||||||
LangEN: "Unsupported output format: %s",
|
|
||||||
},
|
|
||||||
"output_writer_init_failed": {
|
|
||||||
LangZH: "初始化写入器失败: %v",
|
|
||||||
LangEN: "Failed to initialize writer: %v",
|
|
||||||
},
|
|
||||||
"output_writer_closed": {
|
|
||||||
LangZH: "写入器已关闭",
|
|
||||||
LangEN: "Writer is closed",
|
|
||||||
},
|
|
||||||
"output_manager_not_init": {
|
|
||||||
LangZH: "输出管理器未初始化",
|
|
||||||
LangEN: "Output manager not initialized",
|
|
||||||
},
|
|
||||||
"output_manager_closed": {
|
|
||||||
LangZH: "输出管理器已关闭",
|
|
||||||
LangEN: "Output manager is closed",
|
|
||||||
},
|
|
||||||
"output_write_failed": {
|
|
||||||
LangZH: "写入结果失败: %v",
|
|
||||||
LangEN: "Failed to write result: %v",
|
|
||||||
},
|
|
||||||
"output_flush_failed": {
|
|
||||||
LangZH: "刷新写入器失败: %v",
|
|
||||||
LangEN: "Failed to flush writer: %v",
|
|
||||||
},
|
|
||||||
"output_create_file_failed": {
|
|
||||||
LangZH: "创建%s文件失败: %v",
|
|
||||||
LangEN: "Failed to create %s file: %v",
|
|
||||||
},
|
|
||||||
"output_write_header_failed": {
|
|
||||||
LangZH: "写入CSV头部失败: %v",
|
|
||||||
LangEN: "Failed to write CSV header: %v",
|
|
||||||
},
|
|
||||||
"output_open_file_failed": {
|
|
||||||
LangZH: "打开CSV文件失败: %v",
|
|
||||||
LangEN: "Failed to open CSV file: %v",
|
|
||||||
},
|
|
||||||
"output_read_file_failed": {
|
|
||||||
LangZH: "读取CSV文件失败: %v",
|
|
||||||
LangEN: "Failed to read CSV file: %v",
|
|
||||||
},
|
|
||||||
"output_parse_time_failed": {
|
|
||||||
LangZH: "无法解析时间: %s",
|
|
||||||
LangEN: "Failed to parse time: %s",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 代理系统消息 =========================
|
|
||||||
"proxy_init_start": {
|
|
||||||
LangZH: "初始化代理系统",
|
|
||||||
LangEN: "Initializing proxy system",
|
|
||||||
},
|
|
||||||
"proxy_init_success": {
|
|
||||||
LangZH: "代理系统初始化成功",
|
|
||||||
LangEN: "Proxy system initialized successfully",
|
|
||||||
},
|
|
||||||
"proxy_init_failed": {
|
|
||||||
LangZH: "初始化代理配置失败: %v",
|
|
||||||
LangEN: "Failed to initialize proxy configuration: %v",
|
|
||||||
},
|
|
||||||
"proxy_config_sync_failed": {
|
|
||||||
LangZH: "代理配置同步失败: %v",
|
|
||||||
LangEN: "Failed to sync proxy configuration: %v",
|
|
||||||
},
|
|
||||||
"proxy_enabled": {
|
|
||||||
LangZH: "代理已启用: %s %s",
|
|
||||||
LangEN: "Proxy enabled: %s %s",
|
|
||||||
},
|
|
||||||
"proxy_disabled": {
|
|
||||||
LangZH: "代理已禁用",
|
|
||||||
LangEN: "Proxy disabled",
|
|
||||||
},
|
|
||||||
"proxy_connection_failed": {
|
|
||||||
LangZH: "代理连接失败: %v",
|
|
||||||
LangEN: "Proxy connection failed: %v",
|
|
||||||
},
|
|
||||||
"socks5_create_failed": {
|
|
||||||
LangZH: "创建SOCKS5连接失败: %v",
|
|
||||||
LangEN: "Failed to create SOCKS5 connection: %v",
|
|
||||||
},
|
|
||||||
"tls_conn_failed": {
|
|
||||||
LangZH: "TLS连接失败: %v",
|
|
||||||
LangEN: "TLS connection failed: %v",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 系统状态消息 =========================
|
|
||||||
"status_scan_start": {
|
|
||||||
LangZH: "开始扫描",
|
|
||||||
LangEN: "Starting scan",
|
|
||||||
},
|
|
||||||
"status_scan_complete": {
|
|
||||||
LangZH: "扫描完成",
|
|
||||||
LangEN: "Scan completed",
|
|
||||||
},
|
|
||||||
"status_scan_progress": {
|
|
||||||
LangZH: "扫描进度: %d/%d",
|
|
||||||
LangEN: "Scan progress: %d/%d",
|
|
||||||
},
|
|
||||||
"status_target_found": {
|
|
||||||
LangZH: "发现目标: %s",
|
|
||||||
LangEN: "Target found: %s",
|
|
||||||
},
|
|
||||||
"status_service_detected": {
|
|
||||||
LangZH: "检测到服务: %s",
|
|
||||||
LangEN: "Service detected: %s",
|
|
||||||
},
|
|
||||||
"status_vuln_found": {
|
|
||||||
LangZH: "发现漏洞: %s",
|
|
||||||
LangEN: "Vulnerability found: %s",
|
|
||||||
},
|
|
||||||
"status_connection_failed": {
|
|
||||||
LangZH: "连接失败: %s",
|
|
||||||
LangEN: "Connection failed: %s",
|
|
||||||
},
|
|
||||||
"status_timeout": {
|
|
||||||
LangZH: "连接超时: %s",
|
|
||||||
LangEN: "Connection timeout: %s",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 目标解析消息 =========================
|
|
||||||
"target_parse_start": {
|
|
||||||
LangZH: "开始解析目标",
|
|
||||||
LangEN: "Starting target parsing",
|
|
||||||
},
|
|
||||||
"target_parse_complete": {
|
|
||||||
LangZH: "目标解析完成",
|
|
||||||
LangEN: "Target parsing completed",
|
|
||||||
},
|
|
||||||
"target_hosts_found": {
|
|
||||||
LangZH: "目标主机: %s",
|
|
||||||
LangEN: "Target hosts: %s",
|
|
||||||
},
|
|
||||||
"target_hosts_count": {
|
|
||||||
LangZH: "目标主机: %s ... (共%d个)",
|
|
||||||
LangEN: "Target hosts: %s ... (total %d)",
|
|
||||||
},
|
|
||||||
"target_urls_found": {
|
|
||||||
LangZH: "目标URL: %s",
|
|
||||||
LangEN: "Target URLs: %s",
|
|
||||||
},
|
|
||||||
"target_urls_count": {
|
|
||||||
LangZH: "目标URL: %s ... (共%d个)",
|
|
||||||
LangEN: "Target URLs: %s ... (total %d)",
|
|
||||||
},
|
|
||||||
"target_ports_found": {
|
|
||||||
LangZH: "扫描端口: %s",
|
|
||||||
LangEN: "Scan ports: %s",
|
|
||||||
},
|
|
||||||
"target_ports_count": {
|
|
||||||
LangZH: "扫描端口: %s ... (共%d个)",
|
|
||||||
LangEN: "Scan ports: %s ... (total %d)",
|
|
||||||
},
|
|
||||||
"target_exclude_ports": {
|
|
||||||
LangZH: "排除端口: %s",
|
|
||||||
LangEN: "Exclude ports: %s",
|
|
||||||
},
|
|
||||||
"target_local_mode": {
|
|
||||||
LangZH: "本地扫描模式",
|
|
||||||
LangEN: "Local scan mode",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 网络配置消息 =========================
|
|
||||||
"network_http_proxy": {
|
|
||||||
LangZH: "HTTP代理: %s",
|
|
||||||
LangEN: "HTTP proxy: %s",
|
|
||||||
},
|
|
||||||
"network_socks5_proxy": {
|
|
||||||
LangZH: "Socks5代理: %s",
|
|
||||||
LangEN: "Socks5 proxy: %s",
|
|
||||||
},
|
|
||||||
"network_timeout": {
|
|
||||||
LangZH: "连接超时: %v",
|
|
||||||
LangEN: "Connection timeout: %v",
|
|
||||||
},
|
|
||||||
"network_web_timeout": {
|
|
||||||
LangZH: "Web超时: %v",
|
|
||||||
LangEN: "Web timeout: %v",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 凭据相关消息 =========================
|
|
||||||
"credential_username_count": {
|
|
||||||
LangZH: "用户名数量: %d",
|
|
||||||
LangEN: "Username count: %d",
|
|
||||||
},
|
|
||||||
"credential_password_count": {
|
|
||||||
LangZH: "密码数量: %d",
|
|
||||||
LangEN: "Password count: %d",
|
|
||||||
},
|
|
||||||
"credential_hash_count": {
|
|
||||||
LangZH: "Hash数量: %d",
|
|
||||||
LangEN: "Hash count: %d",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 文件操作消息 =========================
|
|
||||||
"file_read_start": {
|
|
||||||
LangZH: "开始读取文件: %s",
|
|
||||||
LangEN: "Starting to read file: %s",
|
|
||||||
},
|
|
||||||
"file_read_complete": {
|
|
||||||
LangZH: "文件读取完成: %s",
|
|
||||||
LangEN: "File reading completed: %s",
|
|
||||||
},
|
|
||||||
"file_read_error": {
|
|
||||||
LangZH: "读取文件错误: %s",
|
|
||||||
LangEN: "File reading error: %s",
|
|
||||||
},
|
|
||||||
"file_not_exist": {
|
|
||||||
LangZH: "文件不存在: %s",
|
|
||||||
LangEN: "File does not exist: %s",
|
|
||||||
},
|
|
||||||
"file_empty": {
|
|
||||||
LangZH: "文件为空: %s",
|
|
||||||
LangEN: "File is empty: %s",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 验证相关消息 =========================
|
|
||||||
"validation_start": {
|
|
||||||
LangZH: "开始配置验证",
|
|
||||||
LangEN: "Starting configuration validation",
|
|
||||||
},
|
|
||||||
"validation_complete": {
|
|
||||||
LangZH: "配置验证完成",
|
|
||||||
LangEN: "Configuration validation completed",
|
|
||||||
},
|
|
||||||
"validation_warning": {
|
|
||||||
LangZH: "验证警告: %s",
|
|
||||||
LangEN: "Validation warning: %s",
|
|
||||||
},
|
|
||||||
"validation_error": {
|
|
||||||
LangZH: "验证错误: %s",
|
|
||||||
LangEN: "Validation error: %s",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 通用错误消息 =========================
|
|
||||||
"error_occurred": {
|
|
||||||
LangZH: "错误: %v",
|
|
||||||
LangEN: "Error: %v",
|
|
||||||
},
|
|
||||||
"error_unknown": {
|
|
||||||
LangZH: "未知错误",
|
|
||||||
LangEN: "Unknown error",
|
|
||||||
},
|
|
||||||
"error_not_implemented": {
|
|
||||||
LangZH: "功能未实现",
|
|
||||||
LangEN: "Feature not implemented",
|
|
||||||
},
|
|
||||||
"error_permission_denied": {
|
|
||||||
LangZH: "权限不足",
|
|
||||||
LangEN: "Permission denied",
|
|
||||||
},
|
|
||||||
"error_resource_busy": {
|
|
||||||
LangZH: "资源忙碌",
|
|
||||||
LangEN: "Resource busy",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 通用状态消息 =========================
|
|
||||||
"status_initializing": {
|
|
||||||
LangZH: "正在初始化...",
|
|
||||||
LangEN: "Initializing...",
|
|
||||||
},
|
|
||||||
"status_processing": {
|
|
||||||
LangZH: "正在处理...",
|
|
||||||
LangEN: "Processing...",
|
|
||||||
},
|
|
||||||
"status_completed": {
|
|
||||||
LangZH: "已完成",
|
|
||||||
LangEN: "Completed",
|
|
||||||
},
|
|
||||||
"status_failed": {
|
|
||||||
LangZH: "失败",
|
|
||||||
LangEN: "Failed",
|
|
||||||
},
|
|
||||||
"status_cancelled": {
|
|
||||||
LangZH: "已取消",
|
|
||||||
LangEN: "Cancelled",
|
|
||||||
},
|
|
||||||
"status_ready": {
|
|
||||||
LangZH: "就绪",
|
|
||||||
LangEN: "Ready",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= Parsers包专用消息 =========================
|
|
||||||
"parser_validation_input_empty": {
|
|
||||||
LangZH: "验证输入为空",
|
|
||||||
LangEN: "Validation input is empty",
|
|
||||||
},
|
|
||||||
"parser_empty_input": {
|
|
||||||
LangZH: "输入参数为空",
|
|
||||||
LangEN: "Input parameters are empty",
|
|
||||||
},
|
|
||||||
"parser_file_empty": {
|
|
||||||
LangZH: "文件名为空",
|
|
||||||
LangEN: "File name is empty",
|
|
||||||
},
|
|
||||||
"parser_file_too_big": {
|
|
||||||
LangZH: "文件过大: %d bytes, 最大限制: %d bytes",
|
|
||||||
LangEN: "File too large: %d bytes, max limit: %d bytes",
|
|
||||||
},
|
|
||||||
"parser_cannot_open_file": {
|
|
||||||
LangZH: "无法打开文件",
|
|
||||||
LangEN: "Cannot open file",
|
|
||||||
},
|
|
||||||
"parser_file_not_exists": {
|
|
||||||
LangZH: "文件不存在或无法访问",
|
|
||||||
LangEN: "File does not exist or cannot be accessed",
|
|
||||||
},
|
|
||||||
"parser_file_read_timeout": {
|
|
||||||
LangZH: "文件读取超时",
|
|
||||||
LangEN: "File read timeout",
|
|
||||||
},
|
|
||||||
"parser_file_scan_failed": {
|
|
||||||
LangZH: "文件扫描失败",
|
|
||||||
LangEN: "File scan failed",
|
|
||||||
},
|
|
||||||
"parser_username_too_long": {
|
|
||||||
LangZH: "用户名过长: %d字符,最大允许: %d",
|
|
||||||
LangEN: "Username too long: %d characters, max allowed: %d",
|
|
||||||
},
|
|
||||||
"parser_username_invalid_chars": {
|
|
||||||
LangZH: "用户名包含非法字符",
|
|
||||||
LangEN: "Username contains invalid characters",
|
|
||||||
},
|
|
||||||
"parser_password_empty": {
|
|
||||||
LangZH: "不允许空密码",
|
|
||||||
LangEN: "Empty passwords not allowed",
|
|
||||||
},
|
|
||||||
"parser_password_too_long": {
|
|
||||||
LangZH: "密码过长: %d字符,最大允许: %d",
|
|
||||||
LangEN: "Password too long: %d characters, max allowed: %d",
|
|
||||||
},
|
|
||||||
"parser_hash_empty": {
|
|
||||||
LangZH: "哈希值为空",
|
|
||||||
LangEN: "Hash value is empty",
|
|
||||||
},
|
|
||||||
"parser_hash_invalid_format": {
|
|
||||||
LangZH: "哈希值格式无效,需要32位十六进制字符",
|
|
||||||
LangEN: "Invalid hash format, requires 32-character hexadecimal",
|
|
||||||
},
|
|
||||||
"parser_proxy_url_invalid": {
|
|
||||||
LangZH: "代理URL格式无效: %v",
|
|
||||||
LangEN: "Invalid proxy URL format: %v",
|
|
||||||
},
|
|
||||||
"parser_proxy_protocol_unsupported": {
|
|
||||||
LangZH: "不支持的代理协议: %s",
|
|
||||||
LangEN: "Unsupported proxy protocol: %s",
|
|
||||||
},
|
|
||||||
"parser_proxy_host_empty": {
|
|
||||||
LangZH: "代理主机名为空",
|
|
||||||
LangEN: "Proxy hostname is empty",
|
|
||||||
},
|
|
||||||
"parser_proxy_port_invalid": {
|
|
||||||
LangZH: "代理端口号无效: %s",
|
|
||||||
LangEN: "Invalid proxy port: %s",
|
|
||||||
},
|
|
||||||
"parser_proxy_port_out_of_range": {
|
|
||||||
LangZH: "代理端口号超出范围: %d",
|
|
||||||
LangEN: "Proxy port out of range: %d",
|
|
||||||
},
|
|
||||||
"parser_proxy_insecure": {
|
|
||||||
LangZH: "不允许使用不安全的HTTP代理",
|
|
||||||
LangEN: "Insecure HTTP proxy not allowed",
|
|
||||||
},
|
|
||||||
"parser_user_agent_too_long": {
|
|
||||||
LangZH: "用户代理字符串过长",
|
|
||||||
LangEN: "User agent string too long",
|
|
||||||
},
|
|
||||||
"parser_user_agent_invalid_chars": {
|
|
||||||
LangZH: "用户代理包含非法字符",
|
|
||||||
LangEN: "User agent contains invalid characters",
|
|
||||||
},
|
|
||||||
"parser_cookie_too_long": {
|
|
||||||
LangZH: "Cookie字符串过长",
|
|
||||||
LangEN: "Cookie string too long",
|
|
||||||
},
|
|
||||||
"parser_error_count_limit": {
|
|
||||||
LangZH: "错误数量过多,仅显示前%d个",
|
|
||||||
LangEN: "Too many errors, showing only first %d",
|
|
||||||
},
|
|
||||||
"parser_no_scan_target": {
|
|
||||||
LangZH: "未指定任何扫描目标",
|
|
||||||
LangEN: "No scan targets specified",
|
|
||||||
},
|
|
||||||
"parser_no_target_default": {
|
|
||||||
LangZH: "未指定扫描目标,将使用默认配置",
|
|
||||||
LangEN: "No scan targets specified, using default configuration",
|
|
||||||
},
|
|
||||||
"parser_multiple_scan_modes": {
|
|
||||||
LangZH: "不能同时使用多种扫描模式",
|
|
||||||
LangEN: "Cannot use multiple scan modes simultaneously",
|
|
||||||
},
|
|
||||||
"parser_proxy_ping_warning": {
|
|
||||||
LangZH: "使用代理时建议禁用Ping检测",
|
|
||||||
LangEN: "Recommend disabling Ping detection when using proxy",
|
|
||||||
},
|
|
||||||
"parser_multiple_modes_conflict": {
|
|
||||||
LangZH: "不能同时指定多种扫描模式(主机扫描、URL扫描、本地模式)",
|
|
||||||
LangEN: "Cannot specify multiple scan modes (host scan, URL scan, local mode) simultaneously",
|
|
||||||
},
|
|
||||||
"parser_proxy_ping_fail": {
|
|
||||||
LangZH: "代理模式下Ping检测可能失效",
|
|
||||||
LangEN: "Ping detection may fail in proxy mode",
|
|
||||||
},
|
|
||||||
"parser_exclude_ports_invalid": {
|
|
||||||
LangZH: "排除端口无效",
|
|
||||||
LangEN: "Exclude ports invalid",
|
|
||||||
},
|
|
||||||
"parser_many_targets_warning": {
|
|
||||||
LangZH: "大量目标(%d),可能耗时较长",
|
|
||||||
LangEN: "Large number of targets (%d), may take a long time",
|
|
||||||
},
|
|
||||||
"parser_too_many_ports": {
|
|
||||||
LangZH: "端口数量过多",
|
|
||||||
LangEN: "Too many ports",
|
|
||||||
},
|
|
||||||
"parser_timeout_too_short": {
|
|
||||||
LangZH: "超时过短",
|
|
||||||
LangEN: "Timeout too short",
|
|
||||||
},
|
|
||||||
"parser_timeout_too_long": {
|
|
||||||
LangZH: "超时过长",
|
|
||||||
LangEN: "Timeout too long",
|
|
||||||
},
|
|
||||||
"parser_invalid_scan_mode": {
|
|
||||||
LangZH: "无效的扫描模式: %s",
|
|
||||||
LangEN: "Invalid scan mode: %s",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 扫描流程消息 =========================
|
|
||||||
"scan_mode_service_selected": {
|
|
||||||
LangZH: "已选择服务扫描模式",
|
|
||||||
LangEN: "Service scan mode selected",
|
|
||||||
},
|
|
||||||
"scan_info_start": {
|
|
||||||
LangZH: "开始信息扫描",
|
|
||||||
LangEN: "Starting information scan",
|
|
||||||
},
|
|
||||||
"scan_host_start": {
|
|
||||||
LangZH: "开始主机扫描",
|
|
||||||
LangEN: "Starting host scan",
|
|
||||||
},
|
|
||||||
"scan_vulnerability_start": {
|
|
||||||
LangZH: "开始漏洞扫描",
|
|
||||||
LangEN: "Starting vulnerability scan",
|
|
||||||
},
|
|
||||||
"scan_no_service_plugins": {
|
|
||||||
LangZH: "未找到可用的服务插件",
|
|
||||||
LangEN: "No available service plugins found",
|
|
||||||
},
|
|
||||||
"scan_vulnerability_plugins": {
|
|
||||||
LangZH: "使用漏洞扫描插件: %s",
|
|
||||||
LangEN: "Using vulnerability scan plugins: %s",
|
|
||||||
},
|
|
||||||
"scan_no_vulnerability_plugins": {
|
|
||||||
LangZH: "未找到可用的漏洞扫描插件",
|
|
||||||
LangEN: "No available vulnerability scan plugins found",
|
|
||||||
},
|
|
||||||
"scan_complete_ports_found": {
|
|
||||||
LangZH: "扫描完成, 发现 %d 个开放端口",
|
|
||||||
LangEN: "Scan completed, found %d open ports",
|
|
||||||
},
|
|
||||||
"scan_alive_ports_count": {
|
|
||||||
LangZH: "存活端口数量: %d",
|
|
||||||
LangEN: "Alive ports count: %d",
|
|
||||||
},
|
|
||||||
"scan_task_complete": {
|
|
||||||
LangZH: "扫描已完成: %d/%d",
|
|
||||||
LangEN: "Scan completed: %d/%d",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 配置验证消息 =========================
|
|
||||||
"config_web_timeout_warning": {
|
|
||||||
LangZH: "Web超时时间大于普通超时时间,可能导致不期望的行为",
|
|
||||||
LangEN: "Web timeout is larger than normal timeout, may cause unexpected behavior",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= Flag参数帮助消息 =========================
|
|
||||||
"flag_host": {
|
|
||||||
LangZH: "目标主机: IP, IP段, IP段文件, 域名",
|
|
||||||
LangEN: "Target host: IP, IP range, IP file, domain",
|
|
||||||
},
|
|
||||||
"flag_exclude_hosts": {
|
|
||||||
LangZH: "排除主机",
|
|
||||||
LangEN: "Exclude hosts",
|
|
||||||
},
|
|
||||||
"flag_ports": {
|
|
||||||
LangZH: "端口: 默认1000个常用端口",
|
|
||||||
LangEN: "Ports: default 1000 common ports",
|
|
||||||
},
|
|
||||||
"flag_exclude_ports": {
|
|
||||||
LangZH: "排除端口",
|
|
||||||
LangEN: "Exclude ports",
|
|
||||||
},
|
|
||||||
"flag_hosts_file": {
|
|
||||||
LangZH: "主机文件",
|
|
||||||
LangEN: "Hosts file",
|
|
||||||
},
|
|
||||||
"flag_ports_file": {
|
|
||||||
LangZH: "端口文件",
|
|
||||||
LangEN: "Ports file",
|
|
||||||
},
|
|
||||||
"flag_scan_mode": {
|
|
||||||
LangZH: "扫描模式: all, portscan, tcpscan, udpscan等",
|
|
||||||
LangEN: "Scan mode: all, portscan, tcpscan, udpscan, etc.",
|
|
||||||
},
|
|
||||||
"flag_thread_num": {
|
|
||||||
LangZH: "端口扫描线程数",
|
|
||||||
LangEN: "Port scan thread count",
|
|
||||||
},
|
|
||||||
"flag_timeout": {
|
|
||||||
LangZH: "端口扫描超时时间",
|
|
||||||
LangEN: "Port scan timeout",
|
|
||||||
},
|
|
||||||
"flag_module_thread_num": {
|
|
||||||
LangZH: "模块线程数",
|
|
||||||
LangEN: "Module thread count",
|
|
||||||
},
|
|
||||||
"flag_global_timeout": {
|
|
||||||
LangZH: "全局超时时间",
|
|
||||||
LangEN: "Global timeout",
|
|
||||||
},
|
|
||||||
"flag_live_top": {
|
|
||||||
LangZH: "存活主机显示数量",
|
|
||||||
LangEN: "Live hosts display count",
|
|
||||||
},
|
|
||||||
"flag_disable_ping": {
|
|
||||||
LangZH: "禁用ping探测",
|
|
||||||
LangEN: "Disable ping detection",
|
|
||||||
},
|
|
||||||
"flag_enable_fingerprint": {
|
|
||||||
LangZH: "启用指纹识别",
|
|
||||||
LangEN: "Enable fingerprinting",
|
|
||||||
},
|
|
||||||
"flag_local_mode": {
|
|
||||||
LangZH: "本地扫描模式",
|
|
||||||
LangEN: "Local scan mode",
|
|
||||||
},
|
|
||||||
"flag_username": {
|
|
||||||
LangZH: "用户名",
|
|
||||||
LangEN: "Username",
|
|
||||||
},
|
|
||||||
"flag_password": {
|
|
||||||
LangZH: "密码",
|
|
||||||
LangEN: "Password",
|
|
||||||
},
|
|
||||||
"flag_add_users": {
|
|
||||||
LangZH: "额外用户名",
|
|
||||||
LangEN: "Additional usernames",
|
|
||||||
},
|
|
||||||
"flag_add_passwords": {
|
|
||||||
LangZH: "额外密码",
|
|
||||||
LangEN: "Additional passwords",
|
|
||||||
},
|
|
||||||
"flag_users_file": {
|
|
||||||
LangZH: "用户名字典文件",
|
|
||||||
LangEN: "Username dictionary file",
|
|
||||||
},
|
|
||||||
"flag_passwords_file": {
|
|
||||||
LangZH: "密码字典文件",
|
|
||||||
LangEN: "Password dictionary file",
|
|
||||||
},
|
|
||||||
"flag_hash_file": {
|
|
||||||
LangZH: "哈希文件",
|
|
||||||
LangEN: "Hash file",
|
|
||||||
},
|
|
||||||
"flag_hash_value": {
|
|
||||||
LangZH: "哈希值",
|
|
||||||
LangEN: "Hash value",
|
|
||||||
},
|
|
||||||
"flag_domain": {
|
|
||||||
LangZH: "域名",
|
|
||||||
LangEN: "Domain name",
|
|
||||||
},
|
|
||||||
"flag_ssh_key": {
|
|
||||||
LangZH: "SSH私钥文件",
|
|
||||||
LangEN: "SSH private key file",
|
|
||||||
},
|
|
||||||
"flag_target_url": {
|
|
||||||
LangZH: "目标URL",
|
|
||||||
LangEN: "Target URL",
|
|
||||||
},
|
|
||||||
"flag_urls_file": {
|
|
||||||
LangZH: "URL文件",
|
|
||||||
LangEN: "URLs file",
|
|
||||||
},
|
|
||||||
"flag_cookie": {
|
|
||||||
LangZH: "HTTP Cookie",
|
|
||||||
LangEN: "HTTP Cookie",
|
|
||||||
},
|
|
||||||
"flag_web_timeout": {
|
|
||||||
LangZH: "Web超时时间",
|
|
||||||
LangEN: "Web timeout",
|
|
||||||
},
|
|
||||||
"flag_http_proxy": {
|
|
||||||
LangZH: "HTTP代理",
|
|
||||||
LangEN: "HTTP proxy",
|
|
||||||
},
|
|
||||||
"flag_socks5_proxy": {
|
|
||||||
LangZH: "SOCKS5代理",
|
|
||||||
LangEN: "SOCKS5 proxy",
|
|
||||||
},
|
|
||||||
"flag_poc_path": {
|
|
||||||
LangZH: "POC脚本路径",
|
|
||||||
LangEN: "POC script path",
|
|
||||||
},
|
|
||||||
"flag_poc_name": {
|
|
||||||
LangZH: "POC名称",
|
|
||||||
LangEN: "POC name",
|
|
||||||
},
|
|
||||||
"flag_poc_full": {
|
|
||||||
LangZH: "全量POC扫描",
|
|
||||||
LangEN: "Full POC scan",
|
|
||||||
},
|
|
||||||
"flag_dns_log": {
|
|
||||||
LangZH: "DNS日志记录",
|
|
||||||
LangEN: "DNS logging",
|
|
||||||
},
|
|
||||||
"flag_poc_num": {
|
|
||||||
LangZH: "POC并发数",
|
|
||||||
LangEN: "POC concurrency",
|
|
||||||
},
|
|
||||||
"flag_no_poc": {
|
|
||||||
LangZH: "禁用POC扫描",
|
|
||||||
LangEN: "Disable POC scan",
|
|
||||||
},
|
|
||||||
"flag_redis_file": {
|
|
||||||
LangZH: "Redis文件",
|
|
||||||
LangEN: "Redis file",
|
|
||||||
},
|
|
||||||
"flag_redis_shell": {
|
|
||||||
LangZH: "Redis Shell",
|
|
||||||
LangEN: "Redis Shell",
|
|
||||||
},
|
|
||||||
"flag_disable_redis": {
|
|
||||||
LangZH: "禁用Redis扫描",
|
|
||||||
LangEN: "Disable Redis scan",
|
|
||||||
},
|
|
||||||
"flag_redis_write_path": {
|
|
||||||
LangZH: "Redis写入路径",
|
|
||||||
LangEN: "Redis write path",
|
|
||||||
},
|
|
||||||
"flag_redis_write_content": {
|
|
||||||
LangZH: "Redis写入内容",
|
|
||||||
LangEN: "Redis write content",
|
|
||||||
},
|
|
||||||
"flag_redis_write_file": {
|
|
||||||
LangZH: "Redis写入文件",
|
|
||||||
LangEN: "Redis write file",
|
|
||||||
},
|
|
||||||
"flag_disable_brute": {
|
|
||||||
LangZH: "禁用暴力破解",
|
|
||||||
LangEN: "Disable brute force",
|
|
||||||
},
|
|
||||||
"flag_max_retries": {
|
|
||||||
LangZH: "最大重试次数",
|
|
||||||
LangEN: "Maximum retries",
|
|
||||||
},
|
|
||||||
"flag_output_file": {
|
|
||||||
LangZH: "输出文件",
|
|
||||||
LangEN: "Output file",
|
|
||||||
},
|
|
||||||
"flag_output_format": {
|
|
||||||
LangZH: "输出格式: txt, json, csv",
|
|
||||||
LangEN: "Output format: txt, json, csv",
|
|
||||||
},
|
|
||||||
"flag_disable_save": {
|
|
||||||
LangZH: "禁用结果保存",
|
|
||||||
LangEN: "Disable result saving",
|
|
||||||
},
|
|
||||||
"flag_silent_mode": {
|
|
||||||
LangZH: "静默模式",
|
|
||||||
LangEN: "Silent mode",
|
|
||||||
},
|
|
||||||
"flag_no_color": {
|
|
||||||
LangZH: "禁用颜色输出",
|
|
||||||
LangEN: "Disable color output",
|
|
||||||
},
|
|
||||||
"flag_log_level": {
|
|
||||||
LangZH: "日志级别",
|
|
||||||
LangEN: "Log level",
|
|
||||||
},
|
|
||||||
"flag_disable_progress": {
|
|
||||||
LangZH: "禁用进度条",
|
|
||||||
LangEN: "Disable progress bar",
|
|
||||||
},
|
|
||||||
"flag_shellcode": {
|
|
||||||
LangZH: "Shellcode",
|
|
||||||
LangEN: "Shellcode",
|
|
||||||
},
|
|
||||||
"flag_language": {
|
|
||||||
LangZH: "语言: zh, en",
|
|
||||||
LangEN: "Language: zh, en",
|
|
||||||
},
|
|
||||||
"flag_help": {
|
|
||||||
LangZH: "显示帮助信息",
|
|
||||||
LangEN: "Show help information",
|
|
||||||
},
|
|
||||||
"flag_version": {
|
|
||||||
LangZH: "显示版本信息",
|
|
||||||
LangEN: "Show version information",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========================= 进度条消息 =========================
|
|
||||||
"progress_scanning_description": {
|
|
||||||
LangZH: "扫描进度",
|
|
||||||
LangEN: "Scanning Progress",
|
|
||||||
},
|
|
||||||
"progress_port_scanning": {
|
|
||||||
LangZH: "端口扫描",
|
|
||||||
LangEN: "Port Scanning",
|
|
||||||
},
|
|
||||||
"progress_scan_completed": {
|
|
||||||
LangZH: "扫描完成:",
|
|
||||||
LangEN: "Scan Completed:",
|
|
||||||
},
|
|
||||||
"progress_port_scan_completed": {
|
|
||||||
LangZH: "端口扫描完成:",
|
|
||||||
LangEN: "Port Scan Completed:",
|
|
||||||
},
|
|
||||||
"progress_open_ports": {
|
|
||||||
LangZH: "开放端口",
|
|
||||||
LangEN: "Open Ports",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 初始化函数
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// init 初始化核心消息到全局管理器
|
|
||||||
func init() {
|
|
||||||
// 将所有核心消息添加到全局管理器
|
|
||||||
AddMessages(coreMessages)
|
|
||||||
}
|
|
79
Common/i18n/messages/config.go
Normal file
79
Common/i18n/messages/config.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
/*
|
||||||
|
config.go - 配置相关消息
|
||||||
|
|
||||||
|
包含配置管理、验证、同步等相关的
|
||||||
|
国际化消息定义。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ConfigMessages 配置相关消息
|
||||||
|
var ConfigMessages = map[string]map[string]string{
|
||||||
|
// ========================= 配置相关消息 =========================
|
||||||
|
"config_sync_start": {
|
||||||
|
LangZH: "开始同步配置",
|
||||||
|
LangEN: "Starting configuration sync",
|
||||||
|
},
|
||||||
|
"config_sync_complete": {
|
||||||
|
LangZH: "配置同步完成",
|
||||||
|
LangEN: "Configuration sync completed",
|
||||||
|
},
|
||||||
|
"config_validation_start": {
|
||||||
|
LangZH: "开始配置验证",
|
||||||
|
LangEN: "Starting configuration validation",
|
||||||
|
},
|
||||||
|
"config_validation_complete": {
|
||||||
|
LangZH: "配置验证完成",
|
||||||
|
LangEN: "Configuration validation completed",
|
||||||
|
},
|
||||||
|
"config_invalid_scan_mode": {
|
||||||
|
LangZH: "无效的扫描模式: %s",
|
||||||
|
LangEN: "Invalid scan mode: %s",
|
||||||
|
},
|
||||||
|
"config_invalid_thread_num": {
|
||||||
|
LangZH: "无效的线程数: %d",
|
||||||
|
LangEN: "Invalid thread number: %d",
|
||||||
|
},
|
||||||
|
"config_invalid_timeout": {
|
||||||
|
LangZH: "无效的超时时间: %v",
|
||||||
|
LangEN: "Invalid timeout: %v",
|
||||||
|
},
|
||||||
|
"config_invalid_proxy": {
|
||||||
|
LangZH: "无效的代理配置: %s",
|
||||||
|
LangEN: "Invalid proxy configuration: %s",
|
||||||
|
},
|
||||||
|
"config_missing_required": {
|
||||||
|
LangZH: "缺少必需的配置项: %s",
|
||||||
|
LangEN: "Missing required configuration: %s",
|
||||||
|
},
|
||||||
|
"config_load_default": {
|
||||||
|
LangZH: "加载默认配置",
|
||||||
|
LangEN: "Loading default configuration",
|
||||||
|
},
|
||||||
|
"config_override_detected": {
|
||||||
|
LangZH: "检测到配置覆盖: %s",
|
||||||
|
LangEN: "Configuration override detected: %s",
|
||||||
|
},
|
||||||
|
"config_web_timeout_warning": {
|
||||||
|
LangZH: "Web超时时间大于普通超时时间,可能导致不期望的行为",
|
||||||
|
LangEN: "Web timeout is larger than normal timeout, may cause unexpected behavior",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 验证相关消息 =========================
|
||||||
|
"validation_start": {
|
||||||
|
LangZH: "开始配置验证",
|
||||||
|
LangEN: "Starting configuration validation",
|
||||||
|
},
|
||||||
|
"validation_complete": {
|
||||||
|
LangZH: "配置验证完成",
|
||||||
|
LangEN: "Configuration validation completed",
|
||||||
|
},
|
||||||
|
"validation_warning": {
|
||||||
|
LangZH: "验证警告: %s",
|
||||||
|
LangEN: "Validation warning: %s",
|
||||||
|
},
|
||||||
|
"validation_error": {
|
||||||
|
LangZH: "验证错误: %s",
|
||||||
|
LangEN: "Validation error: %s",
|
||||||
|
},
|
||||||
|
}
|
13
Common/i18n/messages/constants.go
Normal file
13
Common/i18n/messages/constants.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
/*
|
||||||
|
constants.go - 消息包常量定义
|
||||||
|
|
||||||
|
包含消息包中使用的语言常量,避免循环导入问题。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 语言常量
|
||||||
|
const (
|
||||||
|
LangZH = "zh" // 中文
|
||||||
|
LangEN = "en" // 英文
|
||||||
|
)
|
93
Common/i18n/messages/core.go
Normal file
93
Common/i18n/messages/core.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
/*
|
||||||
|
core.go - 核心系统消息
|
||||||
|
|
||||||
|
包含系统核心功能的国际化消息,包括扫描流程、
|
||||||
|
系统状态、通用错误等基础消息。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// CoreMessages 核心系统消息
|
||||||
|
var CoreMessages = map[string]map[string]string{
|
||||||
|
// ========================= 系统状态消息 =========================
|
||||||
|
"status_scan_start": {
|
||||||
|
LangZH: "开始扫描",
|
||||||
|
LangEN: "Starting scan",
|
||||||
|
},
|
||||||
|
"status_scan_complete": {
|
||||||
|
LangZH: "扫描完成",
|
||||||
|
LangEN: "Scan completed",
|
||||||
|
},
|
||||||
|
"status_scan_progress": {
|
||||||
|
LangZH: "扫描进度: %d/%d",
|
||||||
|
LangEN: "Scan progress: %d/%d",
|
||||||
|
},
|
||||||
|
"status_target_found": {
|
||||||
|
LangZH: "发现目标: %s",
|
||||||
|
LangEN: "Target found: %s",
|
||||||
|
},
|
||||||
|
"status_service_detected": {
|
||||||
|
LangZH: "检测到服务: %s",
|
||||||
|
LangEN: "Service detected: %s",
|
||||||
|
},
|
||||||
|
"status_vuln_found": {
|
||||||
|
LangZH: "发现漏洞: %s",
|
||||||
|
LangEN: "Vulnerability found: %s",
|
||||||
|
},
|
||||||
|
"status_connection_failed": {
|
||||||
|
LangZH: "连接失败: %s",
|
||||||
|
LangEN: "Connection failed: %s",
|
||||||
|
},
|
||||||
|
"status_timeout": {
|
||||||
|
LangZH: "连接超时: %s",
|
||||||
|
LangEN: "Connection timeout: %s",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 通用状态消息 =========================
|
||||||
|
"status_initializing": {
|
||||||
|
LangZH: "正在初始化...",
|
||||||
|
LangEN: "Initializing...",
|
||||||
|
},
|
||||||
|
"status_processing": {
|
||||||
|
LangZH: "正在处理...",
|
||||||
|
LangEN: "Processing...",
|
||||||
|
},
|
||||||
|
"status_completed": {
|
||||||
|
LangZH: "已完成",
|
||||||
|
LangEN: "Completed",
|
||||||
|
},
|
||||||
|
"status_failed": {
|
||||||
|
LangZH: "失败",
|
||||||
|
LangEN: "Failed",
|
||||||
|
},
|
||||||
|
"status_cancelled": {
|
||||||
|
LangZH: "已取消",
|
||||||
|
LangEN: "Cancelled",
|
||||||
|
},
|
||||||
|
"status_ready": {
|
||||||
|
LangZH: "就绪",
|
||||||
|
LangEN: "Ready",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 文件操作消息 =========================
|
||||||
|
"file_read_start": {
|
||||||
|
LangZH: "开始读取文件: %s",
|
||||||
|
LangEN: "Starting to read file: %s",
|
||||||
|
},
|
||||||
|
"file_read_complete": {
|
||||||
|
LangZH: "文件读取完成: %s",
|
||||||
|
LangEN: "File reading completed: %s",
|
||||||
|
},
|
||||||
|
"file_read_error": {
|
||||||
|
LangZH: "读取文件错误: %s",
|
||||||
|
LangEN: "File reading error: %s",
|
||||||
|
},
|
||||||
|
"file_not_exist": {
|
||||||
|
LangZH: "文件不存在: %s",
|
||||||
|
LangEN: "File does not exist: %s",
|
||||||
|
},
|
||||||
|
"file_empty": {
|
||||||
|
LangZH: "文件为空: %s",
|
||||||
|
LangEN: "File is empty: %s",
|
||||||
|
},
|
||||||
|
}
|
33
Common/i18n/messages/error.go
Normal file
33
Common/i18n/messages/error.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
/*
|
||||||
|
error.go - 通用错误消息
|
||||||
|
|
||||||
|
包含通用错误、异常处理等相关的
|
||||||
|
国际化消息定义。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ErrorMessages 通用错误消息
|
||||||
|
var ErrorMessages = map[string]map[string]string{
|
||||||
|
// ========================= 通用错误消息 =========================
|
||||||
|
"error_occurred": {
|
||||||
|
LangZH: "错误: %v",
|
||||||
|
LangEN: "Error: %v",
|
||||||
|
},
|
||||||
|
"error_unknown": {
|
||||||
|
LangZH: "未知错误",
|
||||||
|
LangEN: "Unknown error",
|
||||||
|
},
|
||||||
|
"error_not_implemented": {
|
||||||
|
LangZH: "功能未实现",
|
||||||
|
LangEN: "Feature not implemented",
|
||||||
|
},
|
||||||
|
"error_permission_denied": {
|
||||||
|
LangZH: "权限不足",
|
||||||
|
LangEN: "Permission denied",
|
||||||
|
},
|
||||||
|
"error_resource_busy": {
|
||||||
|
LangZH: "资源忙碌",
|
||||||
|
LangEN: "Resource busy",
|
||||||
|
},
|
||||||
|
}
|
245
Common/i18n/messages/flag.go
Normal file
245
Common/i18n/messages/flag.go
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
/*
|
||||||
|
flag.go - 命令行参数消息
|
||||||
|
|
||||||
|
包含命令行参数帮助信息等相关的
|
||||||
|
国际化消息定义。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// FlagMessages 命令行参数消息
|
||||||
|
var FlagMessages = map[string]map[string]string{
|
||||||
|
// ========================= Flag参数帮助消息 =========================
|
||||||
|
"flag_host": {
|
||||||
|
LangZH: "目标主机: IP, IP段, IP段文件, 域名",
|
||||||
|
LangEN: "Target host: IP, IP range, IP file, domain",
|
||||||
|
},
|
||||||
|
"flag_exclude_hosts": {
|
||||||
|
LangZH: "排除主机",
|
||||||
|
LangEN: "Exclude hosts",
|
||||||
|
},
|
||||||
|
"flag_ports": {
|
||||||
|
LangZH: "端口: 默认1000个常用端口",
|
||||||
|
LangEN: "Ports: default 1000 common ports",
|
||||||
|
},
|
||||||
|
"flag_exclude_ports": {
|
||||||
|
LangZH: "排除端口",
|
||||||
|
LangEN: "Exclude ports",
|
||||||
|
},
|
||||||
|
"flag_hosts_file": {
|
||||||
|
LangZH: "主机文件",
|
||||||
|
LangEN: "Hosts file",
|
||||||
|
},
|
||||||
|
"flag_ports_file": {
|
||||||
|
LangZH: "端口文件",
|
||||||
|
LangEN: "Ports file",
|
||||||
|
},
|
||||||
|
"flag_scan_mode": {
|
||||||
|
LangZH: "扫描模式: all(全部), icmp(存活探测), 或指定插件名称",
|
||||||
|
LangEN: "Scan mode: all(all plugins), icmp(alive detection), or specific plugin names",
|
||||||
|
},
|
||||||
|
"flag_thread_num": {
|
||||||
|
LangZH: "端口扫描线程数",
|
||||||
|
LangEN: "Port scan thread count",
|
||||||
|
},
|
||||||
|
"flag_timeout": {
|
||||||
|
LangZH: "端口扫描超时时间",
|
||||||
|
LangEN: "Port scan timeout",
|
||||||
|
},
|
||||||
|
"flag_module_thread_num": {
|
||||||
|
LangZH: "模块线程数",
|
||||||
|
LangEN: "Module thread count",
|
||||||
|
},
|
||||||
|
"flag_global_timeout": {
|
||||||
|
LangZH: "全局超时时间",
|
||||||
|
LangEN: "Global timeout",
|
||||||
|
},
|
||||||
|
"flag_live_top": {
|
||||||
|
LangZH: "存活主机显示数量",
|
||||||
|
LangEN: "Live hosts display count",
|
||||||
|
},
|
||||||
|
"flag_disable_ping": {
|
||||||
|
LangZH: "禁用ping探测",
|
||||||
|
LangEN: "Disable ping detection",
|
||||||
|
},
|
||||||
|
"flag_enable_fingerprint": {
|
||||||
|
LangZH: "启用指纹识别",
|
||||||
|
LangEN: "Enable fingerprinting",
|
||||||
|
},
|
||||||
|
"flag_local_mode": {
|
||||||
|
LangZH: "本地扫描模式",
|
||||||
|
LangEN: "Local scan mode",
|
||||||
|
},
|
||||||
|
"flag_alive_only": {
|
||||||
|
LangZH: "仅进行存活探测",
|
||||||
|
LangEN: "Alive detection only",
|
||||||
|
},
|
||||||
|
"param_conflict_ao_icmp_both": {
|
||||||
|
LangZH: "提示: 同时指定了 -ao 和 -m icmp,两者功能相同,使用存活探测模式",
|
||||||
|
LangEN: "Note: Both -ao and -m icmp specified, both enable alive detection mode",
|
||||||
|
},
|
||||||
|
"flag_username": {
|
||||||
|
LangZH: "用户名",
|
||||||
|
LangEN: "Username",
|
||||||
|
},
|
||||||
|
"flag_password": {
|
||||||
|
LangZH: "密码",
|
||||||
|
LangEN: "Password",
|
||||||
|
},
|
||||||
|
"flag_add_users": {
|
||||||
|
LangZH: "额外用户名",
|
||||||
|
LangEN: "Additional usernames",
|
||||||
|
},
|
||||||
|
"flag_add_passwords": {
|
||||||
|
LangZH: "额外密码",
|
||||||
|
LangEN: "Additional passwords",
|
||||||
|
},
|
||||||
|
"flag_users_file": {
|
||||||
|
LangZH: "用户名字典文件",
|
||||||
|
LangEN: "Username dictionary file",
|
||||||
|
},
|
||||||
|
"flag_passwords_file": {
|
||||||
|
LangZH: "密码字典文件",
|
||||||
|
LangEN: "Password dictionary file",
|
||||||
|
},
|
||||||
|
"flag_hash_file": {
|
||||||
|
LangZH: "哈希文件",
|
||||||
|
LangEN: "Hash file",
|
||||||
|
},
|
||||||
|
"flag_hash_value": {
|
||||||
|
LangZH: "哈希值",
|
||||||
|
LangEN: "Hash value",
|
||||||
|
},
|
||||||
|
"flag_domain": {
|
||||||
|
LangZH: "域名",
|
||||||
|
LangEN: "Domain name",
|
||||||
|
},
|
||||||
|
"flag_ssh_key": {
|
||||||
|
LangZH: "SSH私钥文件",
|
||||||
|
LangEN: "SSH private key file",
|
||||||
|
},
|
||||||
|
"flag_target_url": {
|
||||||
|
LangZH: "目标URL",
|
||||||
|
LangEN: "Target URL",
|
||||||
|
},
|
||||||
|
"flag_urls_file": {
|
||||||
|
LangZH: "URL文件",
|
||||||
|
LangEN: "URLs file",
|
||||||
|
},
|
||||||
|
"flag_cookie": {
|
||||||
|
LangZH: "HTTP Cookie",
|
||||||
|
LangEN: "HTTP Cookie",
|
||||||
|
},
|
||||||
|
"flag_web_timeout": {
|
||||||
|
LangZH: "Web超时时间",
|
||||||
|
LangEN: "Web timeout",
|
||||||
|
},
|
||||||
|
"flag_http_proxy": {
|
||||||
|
LangZH: "HTTP代理",
|
||||||
|
LangEN: "HTTP proxy",
|
||||||
|
},
|
||||||
|
"flag_socks5_proxy": {
|
||||||
|
LangZH: "SOCKS5代理",
|
||||||
|
LangEN: "SOCKS5 proxy",
|
||||||
|
},
|
||||||
|
"flag_poc_path": {
|
||||||
|
LangZH: "POC脚本路径",
|
||||||
|
LangEN: "POC script path",
|
||||||
|
},
|
||||||
|
"flag_poc_name": {
|
||||||
|
LangZH: "POC名称",
|
||||||
|
LangEN: "POC name",
|
||||||
|
},
|
||||||
|
"flag_poc_full": {
|
||||||
|
LangZH: "全量POC扫描",
|
||||||
|
LangEN: "Full POC scan",
|
||||||
|
},
|
||||||
|
"flag_dns_log": {
|
||||||
|
LangZH: "DNS日志记录",
|
||||||
|
LangEN: "DNS logging",
|
||||||
|
},
|
||||||
|
"flag_poc_num": {
|
||||||
|
LangZH: "POC并发数",
|
||||||
|
LangEN: "POC concurrency",
|
||||||
|
},
|
||||||
|
"flag_no_poc": {
|
||||||
|
LangZH: "禁用POC扫描",
|
||||||
|
LangEN: "Disable POC scan",
|
||||||
|
},
|
||||||
|
"flag_redis_file": {
|
||||||
|
LangZH: "Redis文件",
|
||||||
|
LangEN: "Redis file",
|
||||||
|
},
|
||||||
|
"flag_redis_shell": {
|
||||||
|
LangZH: "Redis Shell",
|
||||||
|
LangEN: "Redis Shell",
|
||||||
|
},
|
||||||
|
"flag_disable_redis": {
|
||||||
|
LangZH: "禁用Redis扫描",
|
||||||
|
LangEN: "Disable Redis scan",
|
||||||
|
},
|
||||||
|
"flag_redis_write_path": {
|
||||||
|
LangZH: "Redis写入路径",
|
||||||
|
LangEN: "Redis write path",
|
||||||
|
},
|
||||||
|
"flag_redis_write_content": {
|
||||||
|
LangZH: "Redis写入内容",
|
||||||
|
LangEN: "Redis write content",
|
||||||
|
},
|
||||||
|
"flag_redis_write_file": {
|
||||||
|
LangZH: "Redis写入文件",
|
||||||
|
LangEN: "Redis write file",
|
||||||
|
},
|
||||||
|
"flag_disable_brute": {
|
||||||
|
LangZH: "禁用暴力破解",
|
||||||
|
LangEN: "Disable brute force",
|
||||||
|
},
|
||||||
|
"flag_max_retries": {
|
||||||
|
LangZH: "最大重试次数",
|
||||||
|
LangEN: "Maximum retries",
|
||||||
|
},
|
||||||
|
"flag_output_file": {
|
||||||
|
LangZH: "输出文件",
|
||||||
|
LangEN: "Output file",
|
||||||
|
},
|
||||||
|
"flag_output_format": {
|
||||||
|
LangZH: "输出格式: txt, json, csv",
|
||||||
|
LangEN: "Output format: txt, json, csv",
|
||||||
|
},
|
||||||
|
"flag_disable_save": {
|
||||||
|
LangZH: "禁用结果保存",
|
||||||
|
LangEN: "Disable result saving",
|
||||||
|
},
|
||||||
|
"flag_silent_mode": {
|
||||||
|
LangZH: "静默模式",
|
||||||
|
LangEN: "Silent mode",
|
||||||
|
},
|
||||||
|
"flag_no_color": {
|
||||||
|
LangZH: "禁用颜色输出",
|
||||||
|
LangEN: "Disable color output",
|
||||||
|
},
|
||||||
|
"flag_log_level": {
|
||||||
|
LangZH: "日志级别",
|
||||||
|
LangEN: "Log level",
|
||||||
|
},
|
||||||
|
"flag_disable_progress": {
|
||||||
|
LangZH: "禁用进度条",
|
||||||
|
LangEN: "Disable progress bar",
|
||||||
|
},
|
||||||
|
"flag_shellcode": {
|
||||||
|
LangZH: "Shellcode",
|
||||||
|
LangEN: "Shellcode",
|
||||||
|
},
|
||||||
|
"flag_language": {
|
||||||
|
LangZH: "语言: zh, en",
|
||||||
|
LangEN: "Language: zh, en",
|
||||||
|
},
|
||||||
|
"flag_help": {
|
||||||
|
LangZH: "显示帮助信息",
|
||||||
|
LangEN: "Show help information",
|
||||||
|
},
|
||||||
|
"flag_version": {
|
||||||
|
LangZH: "显示版本信息",
|
||||||
|
LangEN: "Show version information",
|
||||||
|
},
|
||||||
|
}
|
67
Common/i18n/messages/network.go
Normal file
67
Common/i18n/messages/network.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
/*
|
||||||
|
network.go - 网络相关消息
|
||||||
|
|
||||||
|
包含网络配置、代理设置、连接管理等相关的
|
||||||
|
国际化消息定义。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// NetworkMessages 网络相关消息
|
||||||
|
var NetworkMessages = map[string]map[string]string{
|
||||||
|
// ========================= 网络配置消息 =========================
|
||||||
|
"network_http_proxy": {
|
||||||
|
LangZH: "HTTP代理: %s",
|
||||||
|
LangEN: "HTTP proxy: %s",
|
||||||
|
},
|
||||||
|
"network_socks5_proxy": {
|
||||||
|
LangZH: "Socks5代理: %s",
|
||||||
|
LangEN: "Socks5 proxy: %s",
|
||||||
|
},
|
||||||
|
"network_timeout": {
|
||||||
|
LangZH: "连接超时: %v",
|
||||||
|
LangEN: "Connection timeout: %v",
|
||||||
|
},
|
||||||
|
"network_web_timeout": {
|
||||||
|
LangZH: "Web超时: %v",
|
||||||
|
LangEN: "Web timeout: %v",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 代理系统消息 =========================
|
||||||
|
"proxy_init_start": {
|
||||||
|
LangZH: "初始化代理系统",
|
||||||
|
LangEN: "Initializing proxy system",
|
||||||
|
},
|
||||||
|
"proxy_init_success": {
|
||||||
|
LangZH: "代理系统初始化成功",
|
||||||
|
LangEN: "Proxy system initialized successfully",
|
||||||
|
},
|
||||||
|
"proxy_init_failed": {
|
||||||
|
LangZH: "初始化代理配置失败: %v",
|
||||||
|
LangEN: "Failed to initialize proxy configuration: %v",
|
||||||
|
},
|
||||||
|
"proxy_config_sync_failed": {
|
||||||
|
LangZH: "代理配置同步失败: %v",
|
||||||
|
LangEN: "Failed to sync proxy configuration: %v",
|
||||||
|
},
|
||||||
|
"proxy_enabled": {
|
||||||
|
LangZH: "代理已启用: %s %s",
|
||||||
|
LangEN: "Proxy enabled: %s %s",
|
||||||
|
},
|
||||||
|
"proxy_disabled": {
|
||||||
|
LangZH: "代理已禁用",
|
||||||
|
LangEN: "Proxy disabled",
|
||||||
|
},
|
||||||
|
"proxy_connection_failed": {
|
||||||
|
LangZH: "代理连接失败: %v",
|
||||||
|
LangEN: "Proxy connection failed: %v",
|
||||||
|
},
|
||||||
|
"socks5_create_failed": {
|
||||||
|
LangZH: "创建SOCKS5连接失败: %v",
|
||||||
|
LangEN: "Failed to create SOCKS5 connection: %v",
|
||||||
|
},
|
||||||
|
"tls_conn_failed": {
|
||||||
|
LangZH: "TLS连接失败: %v",
|
||||||
|
LangEN: "TLS connection failed: %v",
|
||||||
|
},
|
||||||
|
}
|
109
Common/i18n/messages/output.go
Normal file
109
Common/i18n/messages/output.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
/*
|
||||||
|
output.go - 输出相关消息
|
||||||
|
|
||||||
|
包含输出系统、文件保存、格式化等相关的
|
||||||
|
国际化消息定义。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// OutputMessages 输出相关消息
|
||||||
|
var OutputMessages = map[string]map[string]string{
|
||||||
|
// ========================= 输出系统消息 =========================
|
||||||
|
"output_init_start": {
|
||||||
|
LangZH: "初始化输出系统",
|
||||||
|
LangEN: "Initializing output system",
|
||||||
|
},
|
||||||
|
"output_init_success": {
|
||||||
|
LangZH: "输出系统初始化成功",
|
||||||
|
LangEN: "Output system initialized successfully",
|
||||||
|
},
|
||||||
|
"output_init_failed": {
|
||||||
|
LangZH: "输出系统初始化失败: %v",
|
||||||
|
LangEN: "Failed to initialize output system: %v",
|
||||||
|
},
|
||||||
|
"output_format_invalid": {
|
||||||
|
LangZH: "无效的输出格式: %s",
|
||||||
|
LangEN: "Invalid output format: %s",
|
||||||
|
},
|
||||||
|
"output_path_empty": {
|
||||||
|
LangZH: "输出路径为空",
|
||||||
|
LangEN: "Output path is empty",
|
||||||
|
},
|
||||||
|
"output_not_init": {
|
||||||
|
LangZH: "输出系统未初始化",
|
||||||
|
LangEN: "Output system not initialized",
|
||||||
|
},
|
||||||
|
"output_saving_result": {
|
||||||
|
LangZH: "保存扫描结果: %s -> %s",
|
||||||
|
LangEN: "Saving scan result: %s -> %s",
|
||||||
|
},
|
||||||
|
"output_save_failed": {
|
||||||
|
LangZH: "保存结果失败: %v",
|
||||||
|
LangEN: "Failed to save result: %v",
|
||||||
|
},
|
||||||
|
"output_closing": {
|
||||||
|
LangZH: "关闭输出系统",
|
||||||
|
LangEN: "Closing output system",
|
||||||
|
},
|
||||||
|
"output_closed": {
|
||||||
|
LangZH: "输出系统已关闭",
|
||||||
|
LangEN: "Output system closed",
|
||||||
|
},
|
||||||
|
"output_close_failed": {
|
||||||
|
LangZH: "关闭输出系统失败: %v",
|
||||||
|
LangEN: "Failed to close output system: %v",
|
||||||
|
},
|
||||||
|
"output_config_nil": {
|
||||||
|
LangZH: "配置不能为空",
|
||||||
|
LangEN: "Configuration cannot be nil",
|
||||||
|
},
|
||||||
|
"output_unsupported_format": {
|
||||||
|
LangZH: "不支持的输出格式: %s",
|
||||||
|
LangEN: "Unsupported output format: %s",
|
||||||
|
},
|
||||||
|
"output_writer_init_failed": {
|
||||||
|
LangZH: "初始化写入器失败: %v",
|
||||||
|
LangEN: "Failed to initialize writer: %v",
|
||||||
|
},
|
||||||
|
"output_writer_closed": {
|
||||||
|
LangZH: "写入器已关闭",
|
||||||
|
LangEN: "Writer is closed",
|
||||||
|
},
|
||||||
|
"output_manager_not_init": {
|
||||||
|
LangZH: "输出管理器未初始化",
|
||||||
|
LangEN: "Output manager not initialized",
|
||||||
|
},
|
||||||
|
"output_manager_closed": {
|
||||||
|
LangZH: "输出管理器已关闭",
|
||||||
|
LangEN: "Output manager is closed",
|
||||||
|
},
|
||||||
|
"output_write_failed": {
|
||||||
|
LangZH: "写入结果失败: %v",
|
||||||
|
LangEN: "Failed to write result: %v",
|
||||||
|
},
|
||||||
|
"output_flush_failed": {
|
||||||
|
LangZH: "刷新写入器失败: %v",
|
||||||
|
LangEN: "Failed to flush writer: %v",
|
||||||
|
},
|
||||||
|
"output_create_file_failed": {
|
||||||
|
LangZH: "创建%s文件失败: %v",
|
||||||
|
LangEN: "Failed to create %s file: %v",
|
||||||
|
},
|
||||||
|
"output_write_header_failed": {
|
||||||
|
LangZH: "写入CSV头部失败: %v",
|
||||||
|
LangEN: "Failed to write CSV header: %v",
|
||||||
|
},
|
||||||
|
"output_open_file_failed": {
|
||||||
|
LangZH: "打开CSV文件失败: %v",
|
||||||
|
LangEN: "Failed to open CSV file: %v",
|
||||||
|
},
|
||||||
|
"output_read_file_failed": {
|
||||||
|
LangZH: "读取CSV文件失败: %v",
|
||||||
|
LangEN: "Failed to read CSV file: %v",
|
||||||
|
},
|
||||||
|
"output_parse_time_failed": {
|
||||||
|
LangZH: "无法解析时间: %s",
|
||||||
|
LangEN: "Failed to parse time: %s",
|
||||||
|
},
|
||||||
|
}
|
287
Common/i18n/messages/parse.go
Normal file
287
Common/i18n/messages/parse.go
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
/*
|
||||||
|
parse.go - 解析相关消息
|
||||||
|
|
||||||
|
包含参数解析、目标解析、凭据解析等相关的
|
||||||
|
国际化消息定义。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ParseMessages 解析相关消息
|
||||||
|
var ParseMessages = map[string]map[string]string{
|
||||||
|
// ========================= 解析错误消息 =========================
|
||||||
|
"parse_error_empty_input": {
|
||||||
|
LangZH: "输入参数为空",
|
||||||
|
LangEN: "Input parameters are empty",
|
||||||
|
},
|
||||||
|
"parse_error_config_failed": {
|
||||||
|
LangZH: "解析配置失败: %v",
|
||||||
|
LangEN: "Failed to parse configuration: %v",
|
||||||
|
},
|
||||||
|
"parse_error_parser_not_init": {
|
||||||
|
LangZH: "解析器未初始化",
|
||||||
|
LangEN: "Parser not initialized",
|
||||||
|
},
|
||||||
|
"parse_error_credential_failed": {
|
||||||
|
LangZH: "凭据解析失败: %v",
|
||||||
|
LangEN: "Failed to parse credentials: %v",
|
||||||
|
},
|
||||||
|
"parse_error_target_failed": {
|
||||||
|
LangZH: "目标解析失败: %v",
|
||||||
|
LangEN: "Failed to parse targets: %v",
|
||||||
|
},
|
||||||
|
"parse_error_network_failed": {
|
||||||
|
LangZH: "网络解析失败: %v",
|
||||||
|
LangEN: "Failed to parse network configuration: %v",
|
||||||
|
},
|
||||||
|
"parse_error_validation_failed": {
|
||||||
|
LangZH: "验证失败: %v",
|
||||||
|
LangEN: "Validation failed: %v",
|
||||||
|
},
|
||||||
|
"parse_error_update_vars_failed": {
|
||||||
|
LangZH: "更新全局变量失败: %v",
|
||||||
|
LangEN: "Failed to update global variables: %v",
|
||||||
|
},
|
||||||
|
"parse_error_target_empty": {
|
||||||
|
LangZH: "目标输入为空",
|
||||||
|
LangEN: "Target input is empty",
|
||||||
|
},
|
||||||
|
"parse_error_credential_empty": {
|
||||||
|
LangZH: "凭据输入为空",
|
||||||
|
LangEN: "Credential input is empty",
|
||||||
|
},
|
||||||
|
"parse_error_network_empty": {
|
||||||
|
LangZH: "网络配置为空",
|
||||||
|
LangEN: "Network configuration is empty",
|
||||||
|
},
|
||||||
|
"parse_error_invalid_ip": {
|
||||||
|
LangZH: "无效的IP地址: %s",
|
||||||
|
LangEN: "Invalid IP address: %s",
|
||||||
|
},
|
||||||
|
"parse_error_invalid_port": {
|
||||||
|
LangZH: "无效的端口: %s",
|
||||||
|
LangEN: "Invalid port: %s",
|
||||||
|
},
|
||||||
|
"parse_error_invalid_url": {
|
||||||
|
LangZH: "无效的URL: %s",
|
||||||
|
LangEN: "Invalid URL: %s",
|
||||||
|
},
|
||||||
|
"parse_error_file_not_found": {
|
||||||
|
LangZH: "文件未找到: %s",
|
||||||
|
LangEN: "File not found: %s",
|
||||||
|
},
|
||||||
|
"parse_error_file_read_failed": {
|
||||||
|
LangZH: "读取文件失败: %s",
|
||||||
|
LangEN: "Failed to read file: %s",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 目标解析消息 =========================
|
||||||
|
"target_parse_start": {
|
||||||
|
LangZH: "开始解析目标",
|
||||||
|
LangEN: "Starting target parsing",
|
||||||
|
},
|
||||||
|
"target_parse_complete": {
|
||||||
|
LangZH: "目标解析完成",
|
||||||
|
LangEN: "Target parsing completed",
|
||||||
|
},
|
||||||
|
"target_hosts_found": {
|
||||||
|
LangZH: "目标主机: %s",
|
||||||
|
LangEN: "Target hosts: %s",
|
||||||
|
},
|
||||||
|
"target_hosts_count": {
|
||||||
|
LangZH: "目标主机: %s ... (共%d个)",
|
||||||
|
LangEN: "Target hosts: %s ... (total %d)",
|
||||||
|
},
|
||||||
|
"target_urls_found": {
|
||||||
|
LangZH: "目标URL: %s",
|
||||||
|
LangEN: "Target URLs: %s",
|
||||||
|
},
|
||||||
|
"target_urls_count": {
|
||||||
|
LangZH: "目标URL: %s ... (共%d个)",
|
||||||
|
LangEN: "Target URLs: %s ... (total %d)",
|
||||||
|
},
|
||||||
|
"target_ports_found": {
|
||||||
|
LangZH: "扫描端口: %s",
|
||||||
|
LangEN: "Scan ports: %s",
|
||||||
|
},
|
||||||
|
"target_ports_count": {
|
||||||
|
LangZH: "扫描端口: %s ... (共%d个)",
|
||||||
|
LangEN: "Scan ports: %s ... (total %d)",
|
||||||
|
},
|
||||||
|
"target_exclude_ports": {
|
||||||
|
LangZH: "排除端口: %s",
|
||||||
|
LangEN: "Exclude ports: %s",
|
||||||
|
},
|
||||||
|
"target_local_mode": {
|
||||||
|
LangZH: "本地扫描模式",
|
||||||
|
LangEN: "Local scan mode",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 凭据相关消息 =========================
|
||||||
|
"credential_username_count": {
|
||||||
|
LangZH: "用户名数量: %d",
|
||||||
|
LangEN: "Username count: %d",
|
||||||
|
},
|
||||||
|
"credential_password_count": {
|
||||||
|
LangZH: "密码数量: %d",
|
||||||
|
LangEN: "Password count: %d",
|
||||||
|
},
|
||||||
|
"credential_hash_count": {
|
||||||
|
LangZH: "Hash数量: %d",
|
||||||
|
LangEN: "Hash count: %d",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= Parsers包专用消息 =========================
|
||||||
|
"parser_validation_input_empty": {
|
||||||
|
LangZH: "验证输入为空",
|
||||||
|
LangEN: "Validation input is empty",
|
||||||
|
},
|
||||||
|
"parser_empty_input": {
|
||||||
|
LangZH: "输入参数为空",
|
||||||
|
LangEN: "Input parameters are empty",
|
||||||
|
},
|
||||||
|
"parser_file_empty": {
|
||||||
|
LangZH: "文件名为空",
|
||||||
|
LangEN: "File name is empty",
|
||||||
|
},
|
||||||
|
"parser_file_too_big": {
|
||||||
|
LangZH: "文件过大: %d bytes, 最大限制: %d bytes",
|
||||||
|
LangEN: "File too large: %d bytes, max limit: %d bytes",
|
||||||
|
},
|
||||||
|
"parser_cannot_open_file": {
|
||||||
|
LangZH: "无法打开文件",
|
||||||
|
LangEN: "Cannot open file",
|
||||||
|
},
|
||||||
|
"parser_file_not_exists": {
|
||||||
|
LangZH: "文件不存在或无法访问",
|
||||||
|
LangEN: "File does not exist or cannot be accessed",
|
||||||
|
},
|
||||||
|
"parser_file_read_timeout": {
|
||||||
|
LangZH: "文件读取超时",
|
||||||
|
LangEN: "File read timeout",
|
||||||
|
},
|
||||||
|
"parser_file_scan_failed": {
|
||||||
|
LangZH: "文件扫描失败",
|
||||||
|
LangEN: "File scan failed",
|
||||||
|
},
|
||||||
|
"parser_username_too_long": {
|
||||||
|
LangZH: "用户名过长: %d字符,最大允许: %d",
|
||||||
|
LangEN: "Username too long: %d characters, max allowed: %d",
|
||||||
|
},
|
||||||
|
"parser_username_invalid_chars": {
|
||||||
|
LangZH: "用户名包含非法字符",
|
||||||
|
LangEN: "Username contains invalid characters",
|
||||||
|
},
|
||||||
|
"parser_password_empty": {
|
||||||
|
LangZH: "不允许空密码",
|
||||||
|
LangEN: "Empty passwords not allowed",
|
||||||
|
},
|
||||||
|
"parser_password_too_long": {
|
||||||
|
LangZH: "密码过长: %d字符,最大允许: %d",
|
||||||
|
LangEN: "Password too long: %d characters, max allowed: %d",
|
||||||
|
},
|
||||||
|
"parser_hash_empty": {
|
||||||
|
LangZH: "哈希值为空",
|
||||||
|
LangEN: "Hash value is empty",
|
||||||
|
},
|
||||||
|
"parser_hash_invalid_format": {
|
||||||
|
LangZH: "哈希值格式无效,需要32位十六进制字符",
|
||||||
|
LangEN: "Invalid hash format, requires 32-character hexadecimal",
|
||||||
|
},
|
||||||
|
"parser_proxy_url_invalid": {
|
||||||
|
LangZH: "代理URL格式无效: %v",
|
||||||
|
LangEN: "Invalid proxy URL format: %v",
|
||||||
|
},
|
||||||
|
"parser_proxy_protocol_unsupported": {
|
||||||
|
LangZH: "不支持的代理协议: %s",
|
||||||
|
LangEN: "Unsupported proxy protocol: %s",
|
||||||
|
},
|
||||||
|
"parser_proxy_host_empty": {
|
||||||
|
LangZH: "代理主机名为空",
|
||||||
|
LangEN: "Proxy hostname is empty",
|
||||||
|
},
|
||||||
|
"parser_proxy_port_invalid": {
|
||||||
|
LangZH: "代理端口号无效: %s",
|
||||||
|
LangEN: "Invalid proxy port: %s",
|
||||||
|
},
|
||||||
|
"parser_proxy_port_out_of_range": {
|
||||||
|
LangZH: "代理端口号超出范围: %d",
|
||||||
|
LangEN: "Proxy port out of range: %d",
|
||||||
|
},
|
||||||
|
"parser_proxy_insecure": {
|
||||||
|
LangZH: "不允许使用不安全的HTTP代理",
|
||||||
|
LangEN: "Insecure HTTP proxy not allowed",
|
||||||
|
},
|
||||||
|
"parser_user_agent_too_long": {
|
||||||
|
LangZH: "用户代理字符串过长",
|
||||||
|
LangEN: "User agent string too long",
|
||||||
|
},
|
||||||
|
"parser_user_agent_invalid_chars": {
|
||||||
|
LangZH: "用户代理包含非法字符",
|
||||||
|
LangEN: "User agent contains invalid characters",
|
||||||
|
},
|
||||||
|
"parser_cookie_too_long": {
|
||||||
|
LangZH: "Cookie字符串过长",
|
||||||
|
LangEN: "Cookie string too long",
|
||||||
|
},
|
||||||
|
"parser_error_count_limit": {
|
||||||
|
LangZH: "错误数量过多,仅显示前%d个",
|
||||||
|
LangEN: "Too many errors, showing only first %d",
|
||||||
|
},
|
||||||
|
"parser_no_scan_target": {
|
||||||
|
LangZH: "未指定任何扫描目标",
|
||||||
|
LangEN: "No scan targets specified",
|
||||||
|
},
|
||||||
|
"parser_no_target_default": {
|
||||||
|
LangZH: "未指定扫描目标,将使用默认配置",
|
||||||
|
LangEN: "No scan targets specified, using default configuration",
|
||||||
|
},
|
||||||
|
"parser_multiple_scan_modes": {
|
||||||
|
LangZH: "不能同时使用多种扫描模式",
|
||||||
|
LangEN: "Cannot use multiple scan modes simultaneously",
|
||||||
|
},
|
||||||
|
"parser_proxy_ping_warning": {
|
||||||
|
LangZH: "使用代理时建议禁用Ping检测",
|
||||||
|
LangEN: "Recommend disabling Ping detection when using proxy",
|
||||||
|
},
|
||||||
|
"parser_multiple_modes_conflict": {
|
||||||
|
LangZH: "不能同时指定多种扫描模式(主机扫描、URL扫描、本地模式)",
|
||||||
|
LangEN: "Cannot specify multiple scan modes (host scan, URL scan, local mode) simultaneously",
|
||||||
|
},
|
||||||
|
"parser_proxy_ping_fail": {
|
||||||
|
LangZH: "代理模式下Ping检测可能失效",
|
||||||
|
LangEN: "Ping detection may fail in proxy mode",
|
||||||
|
},
|
||||||
|
"parser_exclude_ports_invalid": {
|
||||||
|
LangZH: "排除端口无效",
|
||||||
|
LangEN: "Exclude ports invalid",
|
||||||
|
},
|
||||||
|
"parser_many_targets_warning": {
|
||||||
|
LangZH: "大量目标(%d),可能耗时较长",
|
||||||
|
LangEN: "Large number of targets (%d), may take a long time",
|
||||||
|
},
|
||||||
|
"parser_too_many_ports": {
|
||||||
|
LangZH: "端口数量过多",
|
||||||
|
LangEN: "Too many ports",
|
||||||
|
},
|
||||||
|
"parser_timeout_too_short": {
|
||||||
|
LangZH: "超时过短",
|
||||||
|
LangEN: "Timeout too short",
|
||||||
|
},
|
||||||
|
"parser_timeout_too_long": {
|
||||||
|
LangZH: "超时过长",
|
||||||
|
LangEN: "Timeout too long",
|
||||||
|
},
|
||||||
|
"parser_invalid_scan_mode": {
|
||||||
|
LangZH: "无效的扫描模式: %s",
|
||||||
|
LangEN: "Invalid scan mode: %s",
|
||||||
|
},
|
||||||
|
"parse_error_invalid_target_format": {
|
||||||
|
LangZH: "无效的目标地址格式: %s",
|
||||||
|
LangEN: "Invalid target address format: %s",
|
||||||
|
},
|
||||||
|
"parse_error_no_hosts": {
|
||||||
|
LangZH: "解析后没有找到有效的目标主机",
|
||||||
|
LangEN: "No valid target hosts found after parsing",
|
||||||
|
},
|
||||||
|
}
|
235
Common/i18n/messages/scan.go
Normal file
235
Common/i18n/messages/scan.go
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
/*
|
||||||
|
scan.go - 扫描相关消息
|
||||||
|
|
||||||
|
包含扫描流程、模式选择、插件管理等相关的
|
||||||
|
国际化消息定义。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ScanMessages 扫描相关消息
|
||||||
|
var ScanMessages = map[string]map[string]string{
|
||||||
|
// ========================= 扫描流程消息 =========================
|
||||||
|
"scan_mode_service_selected": {
|
||||||
|
LangZH: "已选择服务扫描模式",
|
||||||
|
LangEN: "Service scan mode selected",
|
||||||
|
},
|
||||||
|
"scan_mode_alive_selected": {
|
||||||
|
LangZH: "已选择存活探测模式",
|
||||||
|
LangEN: "Alive detection mode selected",
|
||||||
|
},
|
||||||
|
"scan_mode_local_selected": {
|
||||||
|
LangZH: "已选择本地扫描模式",
|
||||||
|
LangEN: "Local scan mode selected",
|
||||||
|
},
|
||||||
|
"scan_mode_web_selected": {
|
||||||
|
LangZH: "已选择Web扫描模式",
|
||||||
|
LangEN: "Web scan mode selected",
|
||||||
|
},
|
||||||
|
"scan_info_start": {
|
||||||
|
LangZH: "开始信息扫描",
|
||||||
|
LangEN: "Starting information scan",
|
||||||
|
},
|
||||||
|
"scan_host_start": {
|
||||||
|
LangZH: "开始主机扫描",
|
||||||
|
LangEN: "Starting host scan",
|
||||||
|
},
|
||||||
|
"scan_vulnerability_start": {
|
||||||
|
LangZH: "开始漏洞扫描",
|
||||||
|
LangEN: "Starting vulnerability scan",
|
||||||
|
},
|
||||||
|
"scan_no_service_plugins": {
|
||||||
|
LangZH: "未找到可用的服务插件",
|
||||||
|
LangEN: "No available service plugins found",
|
||||||
|
},
|
||||||
|
"scan_vulnerability_plugins": {
|
||||||
|
LangZH: "使用漏洞扫描插件: %s",
|
||||||
|
LangEN: "Using vulnerability scan plugins: %s",
|
||||||
|
},
|
||||||
|
"scan_no_vulnerability_plugins": {
|
||||||
|
LangZH: "未找到可用的漏洞扫描插件",
|
||||||
|
LangEN: "No available vulnerability scan plugins found",
|
||||||
|
},
|
||||||
|
"scan_complete_ports_found": {
|
||||||
|
LangZH: "扫描完成, 发现 %d 个开放端口",
|
||||||
|
LangEN: "Scan completed, found %d open ports",
|
||||||
|
},
|
||||||
|
"scan_alive_ports_count": {
|
||||||
|
LangZH: "存活端口数量: %d",
|
||||||
|
LangEN: "Alive ports count: %d",
|
||||||
|
},
|
||||||
|
"scan_task_complete": {
|
||||||
|
LangZH: "扫描已完成: %d/%d",
|
||||||
|
LangEN: "Scan completed: %d/%d",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 扫描错误消息 =========================
|
||||||
|
"scan_plugin_panic": {
|
||||||
|
LangZH: "[PANIC] 插件 %s 扫描 %s:%s 时崩溃: %v",
|
||||||
|
LangEN: "[PANIC] Plugin %s crashed while scanning %s:%s: %v",
|
||||||
|
},
|
||||||
|
"scan_plugin_not_found": {
|
||||||
|
LangZH: "扫描类型 %v 无对应插件,已跳过",
|
||||||
|
LangEN: "No plugin found for scan type %v, skipped",
|
||||||
|
},
|
||||||
|
"scan_plugin_error": {
|
||||||
|
LangZH: "扫描错误 %v:%v - %v",
|
||||||
|
LangEN: "Scan error %v:%v - %v",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 扫描器插件消息 =========================
|
||||||
|
"scan_local_start": {
|
||||||
|
LangZH: "开始本地信息收集",
|
||||||
|
LangEN: "Starting local information collection",
|
||||||
|
},
|
||||||
|
"scan_service_start": {
|
||||||
|
LangZH: "开始服务扫描",
|
||||||
|
LangEN: "Starting service scan",
|
||||||
|
},
|
||||||
|
"scan_web_start": {
|
||||||
|
LangZH: "开始Web扫描",
|
||||||
|
LangEN: "Starting web scan",
|
||||||
|
},
|
||||||
|
"scan_general_start": {
|
||||||
|
LangZH: "开始扫描",
|
||||||
|
LangEN: "Starting scan",
|
||||||
|
},
|
||||||
|
"scan_mode_local_prefix": {
|
||||||
|
LangZH: "本地模式",
|
||||||
|
LangEN: "Local mode",
|
||||||
|
},
|
||||||
|
"scan_mode_service_prefix": {
|
||||||
|
LangZH: "服务模式",
|
||||||
|
LangEN: "Service mode",
|
||||||
|
},
|
||||||
|
"scan_mode_web_prefix": {
|
||||||
|
LangZH: "Web模式",
|
||||||
|
LangEN: "Web mode",
|
||||||
|
},
|
||||||
|
"scan_plugins_local": {
|
||||||
|
LangZH: "使用本地插件: %s",
|
||||||
|
LangEN: "Using local plugins: %s",
|
||||||
|
},
|
||||||
|
"scan_plugins_service": {
|
||||||
|
LangZH: "使用服务插件: %s",
|
||||||
|
LangEN: "Using service plugins: %s",
|
||||||
|
},
|
||||||
|
"scan_plugins_web": {
|
||||||
|
LangZH: "使用Web插件: %s",
|
||||||
|
LangEN: "Using web plugins: %s",
|
||||||
|
},
|
||||||
|
"scan_plugins_custom_specified": {
|
||||||
|
LangZH: "使用指定插件: %s",
|
||||||
|
LangEN: "Using specified plugins: %s",
|
||||||
|
},
|
||||||
|
"scan_no_local_plugins": {
|
||||||
|
LangZH: "未找到可用的本地插件",
|
||||||
|
LangEN: "No available local plugins found",
|
||||||
|
},
|
||||||
|
"scan_no_web_plugins": {
|
||||||
|
LangZH: "未找到可用的Web插件",
|
||||||
|
LangEN: "No available web plugins found",
|
||||||
|
},
|
||||||
|
"scan_strategy_local_name": {
|
||||||
|
LangZH: "本地扫描",
|
||||||
|
LangEN: "Local Scan",
|
||||||
|
},
|
||||||
|
"scan_strategy_local_desc": {
|
||||||
|
LangZH: "收集本地系统信息",
|
||||||
|
LangEN: "Collect local system information",
|
||||||
|
},
|
||||||
|
"scan_strategy_service_name": {
|
||||||
|
LangZH: "服务扫描",
|
||||||
|
LangEN: "Service Scan",
|
||||||
|
},
|
||||||
|
"scan_strategy_service_desc": {
|
||||||
|
LangZH: "扫描主机服务和漏洞",
|
||||||
|
LangEN: "Scan host services and vulnerabilities",
|
||||||
|
},
|
||||||
|
"scan_strategy_web_name": {
|
||||||
|
LangZH: "Web扫描",
|
||||||
|
LangEN: "Web Scan",
|
||||||
|
},
|
||||||
|
"scan_strategy_web_desc": {
|
||||||
|
LangZH: "扫描Web应用漏洞和信息",
|
||||||
|
LangEN: "Scan web application vulnerabilities and information",
|
||||||
|
},
|
||||||
|
"scan_alive_hosts_count": {
|
||||||
|
LangZH: "存活主机数量: %d",
|
||||||
|
LangEN: "Alive hosts count: %d",
|
||||||
|
},
|
||||||
|
"scan_strategy_alive_name": {
|
||||||
|
LangZH: "存活探测",
|
||||||
|
LangEN: "Alive Detection",
|
||||||
|
},
|
||||||
|
"scan_strategy_alive_desc": {
|
||||||
|
LangZH: "快速探测主机存活状态",
|
||||||
|
LangEN: "Fast detection of host alive status",
|
||||||
|
},
|
||||||
|
"scan_alive_start": {
|
||||||
|
LangZH: "开始存活探测",
|
||||||
|
LangEN: "Starting alive detection",
|
||||||
|
},
|
||||||
|
"scan_alive_single_target": {
|
||||||
|
LangZH: "目标主机: %s",
|
||||||
|
LangEN: "Target host: %s",
|
||||||
|
},
|
||||||
|
"scan_alive_multiple_targets": {
|
||||||
|
LangZH: "目标主机数量: %d (示例: %s)",
|
||||||
|
LangEN: "Target hosts count: %d (example: %s)",
|
||||||
|
},
|
||||||
|
"scan_alive_summary_title": {
|
||||||
|
LangZH: "存活探测结果摘要",
|
||||||
|
LangEN: "Alive Detection Summary",
|
||||||
|
},
|
||||||
|
"scan_alive_total_hosts": {
|
||||||
|
LangZH: "总主机数: %d",
|
||||||
|
LangEN: "Total hosts: %d",
|
||||||
|
},
|
||||||
|
"scan_alive_hosts_found": {
|
||||||
|
LangZH: "存活主机: %d",
|
||||||
|
LangEN: "Alive hosts: %d",
|
||||||
|
},
|
||||||
|
"scan_alive_dead_hosts": {
|
||||||
|
LangZH: "死亡主机: %d",
|
||||||
|
LangEN: "Dead hosts: %d",
|
||||||
|
},
|
||||||
|
"scan_alive_success_rate": {
|
||||||
|
LangZH: "存活率: %.2f%%",
|
||||||
|
LangEN: "Success rate: %.2f%%",
|
||||||
|
},
|
||||||
|
"scan_alive_duration": {
|
||||||
|
LangZH: "扫描耗时: %v",
|
||||||
|
LangEN: "Scan duration: %v",
|
||||||
|
},
|
||||||
|
"scan_alive_hosts_list": {
|
||||||
|
LangZH: "存活主机列表:",
|
||||||
|
LangEN: "Alive hosts list:",
|
||||||
|
},
|
||||||
|
"target_alive": {
|
||||||
|
LangZH: "存活主机: %s (%s)",
|
||||||
|
LangEN: "Alive host: %s (%s)",
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================= 进度条消息 =========================
|
||||||
|
"progress_scanning_description": {
|
||||||
|
LangZH: "扫描进度",
|
||||||
|
LangEN: "Scanning Progress",
|
||||||
|
},
|
||||||
|
"progress_port_scanning": {
|
||||||
|
LangZH: "端口扫描",
|
||||||
|
LangEN: "Port Scanning",
|
||||||
|
},
|
||||||
|
"progress_scan_completed": {
|
||||||
|
LangZH: "扫描完成:",
|
||||||
|
LangEN: "Scan Completed:",
|
||||||
|
},
|
||||||
|
"progress_port_scan_completed": {
|
||||||
|
LangZH: "端口扫描完成:",
|
||||||
|
LangEN: "Port Scan Completed:",
|
||||||
|
},
|
||||||
|
"progress_open_ports": {
|
||||||
|
LangZH: "开放端口",
|
||||||
|
LangEN: "Open Ports",
|
||||||
|
},
|
||||||
|
}
|
@ -273,16 +273,18 @@ func (vp *ValidationParser) checkPerformance(input *ValidationInput, config *Par
|
|||||||
|
|
||||||
// validateScanMode 验证扫描模式
|
// validateScanMode 验证扫描模式
|
||||||
func (vp *ValidationParser) validateScanMode(scanMode string) error {
|
func (vp *ValidationParser) validateScanMode(scanMode string) error {
|
||||||
validModes := []string{"all", "main", "web", "db", "service", "top1000", "custom"}
|
validModes := []string{"all", "icmp"}
|
||||||
|
|
||||||
|
// 检查是否为预定义模式
|
||||||
for _, mode := range validModes {
|
for _, mode := range validModes {
|
||||||
if scanMode == mode {
|
if scanMode == mode {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewParseError("VALIDATION_ERROR",
|
// 允许插件名称作为扫描模式,实际插件验证在运行时进行
|
||||||
fmt.Sprintf("无效的扫描模式: %s", scanMode), "scan_mode", 0, nil)
|
// 这里不做严格验证,避免维护两套插件列表
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
156
Core/AliveScanner.go
Normal file
156
Core/AliveScanner.go
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
"github.com/shadow1ng/fscan/common/parsers"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
AliveScanner.go - 存活探测扫描器
|
||||||
|
|
||||||
|
专门用于主机存活探测,仅执行ICMP/Ping检测,
|
||||||
|
快速识别网络中的存活主机,不进行端口扫描。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AliveScanStrategy 存活探测扫描策略
|
||||||
|
type AliveScanStrategy struct {
|
||||||
|
*BaseScanStrategy
|
||||||
|
startTime time.Time
|
||||||
|
stats AliveStats
|
||||||
|
}
|
||||||
|
|
||||||
|
// AliveStats 存活探测统计信息
|
||||||
|
type AliveStats struct {
|
||||||
|
TotalHosts int // 总主机数
|
||||||
|
AliveHosts int // 存活主机数
|
||||||
|
DeadHosts int // 死亡主机数
|
||||||
|
ScanDuration time.Duration // 扫描耗时
|
||||||
|
SuccessRate float64 // 成功率
|
||||||
|
AliveHostList []string // 存活主机列表
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAliveScanStrategy 创建新的存活探测扫描策略
|
||||||
|
func NewAliveScanStrategy() *AliveScanStrategy {
|
||||||
|
return &AliveScanStrategy{
|
||||||
|
BaseScanStrategy: NewBaseScanStrategy("存活探测", FilterNone),
|
||||||
|
startTime: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name 返回策略名称
|
||||||
|
func (s *AliveScanStrategy) Name() string {
|
||||||
|
return i18n.GetText("scan_strategy_alive_name")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Description 返回策略描述
|
||||||
|
func (s *AliveScanStrategy) Description() string {
|
||||||
|
return i18n.GetText("scan_strategy_alive_desc")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute 执行存活探测扫描策略
|
||||||
|
func (s *AliveScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
|
// 验证扫描目标
|
||||||
|
if info.Host == "" {
|
||||||
|
common.LogError(i18n.GetText("parse_error_target_empty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出存活探测开始信息
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_start"))
|
||||||
|
|
||||||
|
// 执行存活探测
|
||||||
|
s.performAliveScan(info)
|
||||||
|
|
||||||
|
// 输出统计信息
|
||||||
|
s.outputStats()
|
||||||
|
}
|
||||||
|
|
||||||
|
// performAliveScan 执行存活探测
|
||||||
|
func (s *AliveScanStrategy) performAliveScan(info common.HostInfo) {
|
||||||
|
// 解析目标主机
|
||||||
|
hosts, err := parsers.ParseIP(info.Host, common.HostsFile, common.ExcludeHosts)
|
||||||
|
if err != nil {
|
||||||
|
common.LogError(i18n.GetText("parse_error_target_failed", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hosts) == 0 {
|
||||||
|
common.LogError(i18n.GetText("parse_error_no_hosts"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化统计信息
|
||||||
|
s.stats.TotalHosts = len(hosts)
|
||||||
|
s.stats.AliveHosts = 0
|
||||||
|
s.stats.DeadHosts = 0
|
||||||
|
|
||||||
|
// 显示扫描信息
|
||||||
|
if len(hosts) == 1 {
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_single_target", hosts[0]))
|
||||||
|
} else {
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_multiple_targets", len(hosts), hosts[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行存活检测
|
||||||
|
aliveList := CheckLive(hosts, false) // 使用ICMP探测
|
||||||
|
|
||||||
|
// 更新统计信息
|
||||||
|
s.stats.AliveHosts = len(aliveList)
|
||||||
|
s.stats.DeadHosts = s.stats.TotalHosts - s.stats.AliveHosts
|
||||||
|
s.stats.ScanDuration = time.Since(s.startTime)
|
||||||
|
s.stats.AliveHostList = aliveList // 存储存活主机列表
|
||||||
|
|
||||||
|
if s.stats.TotalHosts > 0 {
|
||||||
|
s.stats.SuccessRate = float64(s.stats.AliveHosts) / float64(s.stats.TotalHosts) * 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// outputStats 输出详细统计信息
|
||||||
|
func (s *AliveScanStrategy) outputStats() {
|
||||||
|
// 输出分隔线
|
||||||
|
common.LogBase("=" + strings.Repeat("=", 60))
|
||||||
|
|
||||||
|
// 输出扫描结果摘要
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_summary_title"))
|
||||||
|
|
||||||
|
// 基础统计
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_total_hosts", s.stats.TotalHosts))
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_hosts_found", s.stats.AliveHosts))
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_dead_hosts", s.stats.DeadHosts))
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_success_rate", s.stats.SuccessRate))
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_duration", s.stats.ScanDuration.Round(time.Millisecond)))
|
||||||
|
|
||||||
|
// 如果有存活主机,显示详细列表
|
||||||
|
if s.stats.AliveHosts > 0 {
|
||||||
|
common.LogBase("")
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_hosts_list"))
|
||||||
|
|
||||||
|
for i, host := range s.stats.AliveHostList {
|
||||||
|
common.LogSuccess(fmt.Sprintf(" [%d] %s", i+1, host))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出分隔线
|
||||||
|
common.LogBase("=" + strings.Repeat("=", 60))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareTargets 存活探测不需要准备扫描目标
|
||||||
|
func (s *AliveScanStrategy) PrepareTargets(info common.HostInfo) []common.HostInfo {
|
||||||
|
// 存活探测不需要返回目标列表,因为它不进行后续扫描
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlugins 存活探测不使用插件
|
||||||
|
func (s *AliveScanStrategy) GetPlugins() ([]string, bool) {
|
||||||
|
return []string{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPluginApplicable 存活探测不适用任何插件
|
||||||
|
func (s *AliveScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
||||||
|
return false
|
||||||
|
}
|
212
Core/BaseScanStrategy.go
Normal file
212
Core/BaseScanStrategy.go
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
BaseScanStrategy.go - 扫描策略基础类
|
||||||
|
|
||||||
|
提供所有扫描策略的通用功能,包括插件管理、验证、
|
||||||
|
日志输出等,减少代码重复并提升维护性。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// PluginFilterType 插件过滤类型
|
||||||
|
type PluginFilterType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FilterNone PluginFilterType = iota // 不过滤
|
||||||
|
FilterLocal // 仅本地插件
|
||||||
|
FilterService // 仅服务插件(排除本地)
|
||||||
|
FilterWeb // 仅Web插件
|
||||||
|
)
|
||||||
|
|
||||||
|
// BaseScanStrategy 扫描策略基础类
|
||||||
|
type BaseScanStrategy struct {
|
||||||
|
strategyName string
|
||||||
|
filterType PluginFilterType
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBaseScanStrategy 创建基础扫描策略
|
||||||
|
func NewBaseScanStrategy(name string, filterType PluginFilterType) *BaseScanStrategy {
|
||||||
|
return &BaseScanStrategy{
|
||||||
|
strategyName: name,
|
||||||
|
filterType: filterType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 插件管理通用方法
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// GetPlugins 获取插件列表(通用实现)
|
||||||
|
func (b *BaseScanStrategy) GetPlugins() ([]string, bool) {
|
||||||
|
// 如果指定了特定插件且不是"all"
|
||||||
|
if common.ScanMode != "" && common.ScanMode != "all" {
|
||||||
|
requestedPlugins := parsePluginList(common.ScanMode)
|
||||||
|
if len(requestedPlugins) == 0 {
|
||||||
|
requestedPlugins = []string{common.ScanMode}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证插件是否存在
|
||||||
|
var validPlugins []string
|
||||||
|
for _, name := range requestedPlugins {
|
||||||
|
if _, exists := common.PluginManager[name]; exists {
|
||||||
|
validPlugins = append(validPlugins, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validPlugins, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未指定或使用"all":获取所有插件,由IsPluginApplicable做类型过滤
|
||||||
|
return GetAllPlugins(), false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetApplicablePlugins 获取适用的插件列表(用于日志显示)
|
||||||
|
func (b *BaseScanStrategy) GetApplicablePlugins(allPlugins []string, isCustomMode bool) []string {
|
||||||
|
if isCustomMode {
|
||||||
|
return allPlugins
|
||||||
|
}
|
||||||
|
|
||||||
|
var applicablePlugins []string
|
||||||
|
for _, pluginName := range allPlugins {
|
||||||
|
plugin, exists := common.PluginManager[pluginName]
|
||||||
|
if !exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.isPluginTypeMatched(plugin) {
|
||||||
|
applicablePlugins = append(applicablePlugins, pluginName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return applicablePlugins
|
||||||
|
}
|
||||||
|
|
||||||
|
// isPluginTypeMatched 检查插件类型是否匹配过滤器
|
||||||
|
func (b *BaseScanStrategy) isPluginTypeMatched(plugin common.ScanPlugin) bool {
|
||||||
|
switch b.filterType {
|
||||||
|
case FilterLocal:
|
||||||
|
return plugin.HasType(common.PluginTypeLocal)
|
||||||
|
case FilterService:
|
||||||
|
return !plugin.HasType(common.PluginTypeLocal)
|
||||||
|
case FilterWeb:
|
||||||
|
return plugin.HasType(common.PluginTypeWeb)
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPluginApplicable 判断插件是否适用(通用实现)
|
||||||
|
func (b *BaseScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
||||||
|
// 自定义模式下运行所有明确指定的插件
|
||||||
|
if isCustomMode {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查插件类型过滤
|
||||||
|
if !b.isPluginTypeMatched(plugin) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于服务扫描,还需检查端口匹配
|
||||||
|
if b.filterType == FilterService {
|
||||||
|
// 无端口限制的插件适用于所有端口
|
||||||
|
if len(plugin.Ports) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 有端口限制的插件:检查端口是否匹配
|
||||||
|
if targetPort > 0 {
|
||||||
|
return plugin.HasPort(targetPort)
|
||||||
|
}
|
||||||
|
// 如果没有提供目标端口,则不执行有端口限制的插件
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 日志输出通用方法
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// LogPluginInfo 输出插件信息(通用实现)
|
||||||
|
func (b *BaseScanStrategy) LogPluginInfo() {
|
||||||
|
allPlugins, isCustomMode := b.GetPlugins()
|
||||||
|
applicablePlugins := b.GetApplicablePlugins(allPlugins, isCustomMode)
|
||||||
|
|
||||||
|
// 生成日志消息
|
||||||
|
var messageKey, prefix string
|
||||||
|
switch b.filterType {
|
||||||
|
case FilterLocal:
|
||||||
|
messageKey = "scan_plugins_local"
|
||||||
|
prefix = i18n.GetText("scan_mode_local_prefix")
|
||||||
|
case FilterService:
|
||||||
|
messageKey = "scan_plugins_service"
|
||||||
|
prefix = i18n.GetText("scan_mode_service_prefix")
|
||||||
|
case FilterWeb:
|
||||||
|
messageKey = "scan_plugins_web"
|
||||||
|
prefix = i18n.GetText("scan_mode_web_prefix")
|
||||||
|
default:
|
||||||
|
messageKey = "scan_plugins_custom"
|
||||||
|
prefix = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(applicablePlugins) > 0 {
|
||||||
|
if isCustomMode {
|
||||||
|
common.LogBase(fmt.Sprintf("%s: %s", prefix,
|
||||||
|
i18n.GetText("scan_plugins_custom_specified", strings.Join(applicablePlugins, ", "))))
|
||||||
|
} else {
|
||||||
|
common.LogBase(fmt.Sprintf("%s: %s", prefix,
|
||||||
|
i18n.GetText(messageKey, strings.Join(applicablePlugins, ", "))))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
noPluginsKey := fmt.Sprintf("scan_no_%s_plugins", b.getFilterTypeName())
|
||||||
|
common.LogBase(fmt.Sprintf("%s: %s", prefix, i18n.GetText(noPluginsKey)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getFilterTypeName 获取过滤器类型名称
|
||||||
|
func (b *BaseScanStrategy) getFilterTypeName() string {
|
||||||
|
switch b.filterType {
|
||||||
|
case FilterLocal:
|
||||||
|
return "local"
|
||||||
|
case FilterService:
|
||||||
|
return "service"
|
||||||
|
case FilterWeb:
|
||||||
|
return "web"
|
||||||
|
default:
|
||||||
|
return "general"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 验证通用方法
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ValidateConfiguration 验证扫描配置(通用实现)
|
||||||
|
func (b *BaseScanStrategy) ValidateConfiguration() error {
|
||||||
|
return validateScanPlugins()
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 通用辅助方法
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// LogScanStart 输出扫描开始信息
|
||||||
|
func (b *BaseScanStrategy) LogScanStart() {
|
||||||
|
switch b.filterType {
|
||||||
|
case FilterLocal:
|
||||||
|
common.LogBase(i18n.GetText("scan_local_start"))
|
||||||
|
case FilterService:
|
||||||
|
common.LogBase(i18n.GetText("scan_service_start"))
|
||||||
|
case FilterWeb:
|
||||||
|
common.LogBase(i18n.GetText("scan_web_start"))
|
||||||
|
default:
|
||||||
|
common.LogBase(i18n.GetText("scan_general_start"))
|
||||||
|
}
|
||||||
|
}
|
38
Core/ICMP.go
38
Core/ICMP.go
@ -16,25 +16,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
AliveHosts []string // 存活主机列表
|
livewg sync.WaitGroup // 存活检测等待组
|
||||||
ExistHosts = make(map[string]struct{}) // 已发现主机记录
|
|
||||||
livewg sync.WaitGroup // 存活检测等待组
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckLive 检测主机存活状态
|
// CheckLive 检测主机存活状态
|
||||||
func CheckLive(hostslist []string, Ping bool) []string {
|
func CheckLive(hostslist []string, Ping bool) []string {
|
||||||
|
// 创建局部存活主机列表,预分配容量避免频繁扩容
|
||||||
|
aliveHosts := make([]string, 0, len(hostslist))
|
||||||
|
existHosts := make(map[string]struct{}, len(hostslist))
|
||||||
|
|
||||||
// 创建主机通道
|
// 创建主机通道
|
||||||
chanHosts := make(chan string, len(hostslist))
|
chanHosts := make(chan string, len(hostslist))
|
||||||
|
|
||||||
// 处理存活主机
|
// 处理存活主机
|
||||||
go handleAliveHosts(chanHosts, hostslist, Ping)
|
go handleAliveHosts(chanHosts, hostslist, Ping, &aliveHosts, existHosts)
|
||||||
|
|
||||||
// 根据Ping参数选择检测方式
|
// 根据Ping参数选择检测方式
|
||||||
if Ping {
|
if Ping {
|
||||||
// 使用ping方式探测
|
// 使用ping方式探测
|
||||||
RunPing(hostslist, chanHosts)
|
RunPing(hostslist, chanHosts)
|
||||||
} else {
|
} else {
|
||||||
probeWithICMP(hostslist, chanHosts)
|
probeWithICMP(hostslist, chanHosts, &aliveHosts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 等待所有检测完成
|
// 等待所有检测完成
|
||||||
@ -42,9 +44,9 @@ func CheckLive(hostslist []string, Ping bool) []string {
|
|||||||
close(chanHosts)
|
close(chanHosts)
|
||||||
|
|
||||||
// 输出存活统计信息
|
// 输出存活统计信息
|
||||||
printAliveStats(hostslist)
|
printAliveStats(aliveHosts, hostslist)
|
||||||
|
|
||||||
return AliveHosts
|
return aliveHosts
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsContain 检查切片中是否包含指定元素
|
// IsContain 检查切片中是否包含指定元素
|
||||||
@ -57,11 +59,11 @@ func IsContain(items []string, item string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
|
func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool, aliveHosts *[]string, existHosts map[string]struct{}) {
|
||||||
for ip := range chanHosts {
|
for ip := range chanHosts {
|
||||||
if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) {
|
if _, ok := existHosts[ip]; !ok && IsContain(hostslist, ip) {
|
||||||
ExistHosts[ip] = struct{}{}
|
existHosts[ip] = struct{}{}
|
||||||
AliveHosts = append(AliveHosts, ip)
|
*aliveHosts = append(*aliveHosts, ip)
|
||||||
|
|
||||||
// 使用Output系统保存存活主机信息
|
// 使用Output系统保存存活主机信息
|
||||||
protocol := "ICMP"
|
protocol := "ICMP"
|
||||||
@ -90,11 +92,11 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// probeWithICMP 使用ICMP方式探测
|
// probeWithICMP 使用ICMP方式探测
|
||||||
func probeWithICMP(hostslist []string, chanHosts chan string) {
|
func probeWithICMP(hostslist []string, chanHosts chan string, aliveHosts *[]string) {
|
||||||
// 尝试监听本地ICMP
|
// 尝试监听本地ICMP
|
||||||
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
RunIcmp1(hostslist, conn, chanHosts)
|
RunIcmp1(hostslist, conn, chanHosts, aliveHosts)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,13 +136,13 @@ func getOptimalTopCount(totalHosts int) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// printAliveStats 打印存活统计信息
|
// printAliveStats 打印存活统计信息
|
||||||
func printAliveStats(hostslist []string) {
|
func printAliveStats(aliveHosts []string, hostslist []string) {
|
||||||
// 智能计算显示数量
|
// 智能计算显示数量
|
||||||
topCount := getOptimalTopCount(len(hostslist))
|
topCount := getOptimalTopCount(len(hostslist))
|
||||||
|
|
||||||
// 大规模扫描时输出 /16 网段统计
|
// 大规模扫描时输出 /16 网段统计
|
||||||
if len(hostslist) > 1000 {
|
if len(hostslist) > 1000 {
|
||||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, topCount, true)
|
arrTop, arrLen := ArrayCountValueTop(aliveHosts, topCount, true)
|
||||||
for i := 0; i < len(arrTop); i++ {
|
for i := 0; i < len(arrTop); i++ {
|
||||||
common.LogInfo(i18n.GetText("subnet_16_alive", arrTop[i], arrLen[i]))
|
common.LogInfo(i18n.GetText("subnet_16_alive", arrTop[i], arrLen[i]))
|
||||||
}
|
}
|
||||||
@ -148,7 +150,7 @@ func printAliveStats(hostslist []string) {
|
|||||||
|
|
||||||
// 输出 /24 网段统计
|
// 输出 /24 网段统计
|
||||||
if len(hostslist) > 256 {
|
if len(hostslist) > 256 {
|
||||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, topCount, false)
|
arrTop, arrLen := ArrayCountValueTop(aliveHosts, topCount, false)
|
||||||
for i := 0; i < len(arrTop); i++ {
|
for i := 0; i < len(arrTop); i++ {
|
||||||
common.LogInfo(i18n.GetText("subnet_24_alive", arrTop[i], arrLen[i]))
|
common.LogInfo(i18n.GetText("subnet_24_alive", arrTop[i], arrLen[i]))
|
||||||
}
|
}
|
||||||
@ -156,7 +158,7 @@ func printAliveStats(hostslist []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RunIcmp1 使用ICMP批量探测主机存活(监听模式)
|
// RunIcmp1 使用ICMP批量探测主机存活(监听模式)
|
||||||
func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) {
|
func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string, aliveHosts *[]string) {
|
||||||
endflag := false
|
endflag := false
|
||||||
|
|
||||||
// 启动监听协程
|
// 启动监听协程
|
||||||
@ -186,7 +188,7 @@ func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string)
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
for {
|
for {
|
||||||
// 所有主机都已响应则退出
|
// 所有主机都已响应则退出
|
||||||
if len(AliveHosts) == len(hostslist) {
|
if len(*aliveHosts) == len(hostslist) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,36 +1,40 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"strings"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalScanStrategy 本地扫描策略
|
// LocalScanStrategy 本地扫描策略
|
||||||
type LocalScanStrategy struct{}
|
type LocalScanStrategy struct {
|
||||||
|
*BaseScanStrategy
|
||||||
|
}
|
||||||
|
|
||||||
// NewLocalScanStrategy 创建新的本地扫描策略
|
// NewLocalScanStrategy 创建新的本地扫描策略
|
||||||
func NewLocalScanStrategy() *LocalScanStrategy {
|
func NewLocalScanStrategy() *LocalScanStrategy {
|
||||||
return &LocalScanStrategy{}
|
return &LocalScanStrategy{
|
||||||
|
BaseScanStrategy: NewBaseScanStrategy("本地扫描", FilterLocal),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name 返回策略名称
|
// Name 返回策略名称
|
||||||
func (s *LocalScanStrategy) Name() string {
|
func (s *LocalScanStrategy) Name() string {
|
||||||
return "本地扫描"
|
return i18n.GetText("scan_strategy_local_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description 返回策略描述
|
// Description 返回策略描述
|
||||||
func (s *LocalScanStrategy) Description() string {
|
func (s *LocalScanStrategy) Description() string {
|
||||||
return "收集本地系统信息"
|
return i18n.GetText("scan_strategy_local_desc")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute 执行本地扫描策略
|
// Execute 执行本地扫描策略
|
||||||
func (s *LocalScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func (s *LocalScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
common.LogBase("执行本地信息收集")
|
// 输出扫描开始信息
|
||||||
|
s.LogScanStart()
|
||||||
|
|
||||||
// 验证插件配置
|
// 验证插件配置
|
||||||
if err := validateScanPlugins(); err != nil {
|
if err := s.ValidateConfiguration(); err != nil {
|
||||||
common.LogError(err.Error())
|
common.LogError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -50,63 +54,3 @@ func (s *LocalScanStrategy) PrepareTargets(info common.HostInfo) []common.HostIn
|
|||||||
// 本地扫描只使用传入的目标信息,不做额外处理
|
// 本地扫描只使用传入的目标信息,不做额外处理
|
||||||
return []common.HostInfo{info}
|
return []common.HostInfo{info}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlugins 获取本地扫描插件列表
|
|
||||||
func (s *LocalScanStrategy) GetPlugins() ([]string, bool) {
|
|
||||||
// 如果指定了特定插件且不是"all"
|
|
||||||
if common.ScanMode != "" && common.ScanMode != "all" {
|
|
||||||
requestedPlugins := parsePluginList(common.ScanMode)
|
|
||||||
if len(requestedPlugins) == 0 {
|
|
||||||
requestedPlugins = []string{common.ScanMode}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证插件是否存在,不做Local类型过滤
|
|
||||||
var validPlugins []string
|
|
||||||
for _, name := range requestedPlugins {
|
|
||||||
if _, exists := common.PluginManager[name]; exists {
|
|
||||||
validPlugins = append(validPlugins, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return validPlugins, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未指定或使用"all":获取所有插件,由IsPluginApplicable做类型过滤
|
|
||||||
return GetAllPlugins(), false
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogPluginInfo 输出本地扫描插件信息
|
|
||||||
func (s *LocalScanStrategy) LogPluginInfo() {
|
|
||||||
allPlugins, isCustomMode := s.GetPlugins()
|
|
||||||
|
|
||||||
// 如果是自定义模式,直接显示用户指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
common.LogBase(fmt.Sprintf("本地模式: 使用指定插件: %s", strings.Join(allPlugins, ", ")))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在自动模式下,只显示Local类型的插件
|
|
||||||
var applicablePlugins []string
|
|
||||||
for _, pluginName := range allPlugins {
|
|
||||||
plugin, exists := common.PluginManager[pluginName]
|
|
||||||
if exists && plugin.HasType(common.PluginTypeLocal) {
|
|
||||||
applicablePlugins = append(applicablePlugins, pluginName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(applicablePlugins) > 0 {
|
|
||||||
common.LogBase(fmt.Sprintf("本地模式: 使用本地插件: %s", strings.Join(applicablePlugins, ", ")))
|
|
||||||
} else {
|
|
||||||
common.LogBase("本地模式: 未找到可用的本地插件")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPluginApplicable 判断插件是否适用于本地扫描
|
|
||||||
func (s *LocalScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
|
||||||
// 自定义模式下运行所有明确指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// 非自定义模式下,只运行Local类型插件
|
|
||||||
return plugin.HasType(common.PluginTypeLocal)
|
|
||||||
}
|
|
||||||
|
98
Core/PortDiscoveryService.go
Normal file
98
Core/PortDiscoveryService.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
"github.com/shadow1ng/fscan/common/parsers"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
PortDiscoveryService.go - 端口发现服务
|
||||||
|
|
||||||
|
负责主机存活检测、端口扫描等端口发现相关功能,
|
||||||
|
从ServiceScanner中分离出来提高代码可维护性。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// PortDiscoveryService 端口发现服务
|
||||||
|
type PortDiscoveryService struct{}
|
||||||
|
|
||||||
|
// NewPortDiscoveryService 创建端口发现服务
|
||||||
|
func NewPortDiscoveryService() *PortDiscoveryService {
|
||||||
|
return &PortDiscoveryService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscoverTargets 发现目标主机和端口
|
||||||
|
func (p *PortDiscoveryService) DiscoverTargets(hostInput string, baseInfo common.HostInfo) ([]common.HostInfo, error) {
|
||||||
|
// 解析目标主机
|
||||||
|
hosts, err := parsers.ParseIP(hostInput, common.HostsFile, common.ExcludeHosts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(i18n.GetText("parse_error_target_failed"), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetInfos []common.HostInfo
|
||||||
|
|
||||||
|
// 主机存活性检测和端口扫描
|
||||||
|
if len(hosts) > 0 || len(common.HostPort) > 0 {
|
||||||
|
// 主机存活检测
|
||||||
|
if p.shouldPerformLivenessCheck(hosts) {
|
||||||
|
hosts = CheckLive(hosts, false)
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_hosts_count", len(hosts)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 端口扫描
|
||||||
|
alivePorts := p.discoverAlivePorts(hosts)
|
||||||
|
if len(alivePorts) > 0 {
|
||||||
|
targetInfos = p.convertToTargetInfos(alivePorts, baseInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetInfos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldPerformLivenessCheck 判断是否需要执行存活性检测
|
||||||
|
func (p *PortDiscoveryService) shouldPerformLivenessCheck(hosts []string) bool {
|
||||||
|
return common.DisablePing == false && len(hosts) > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// discoverAlivePorts 发现存活的端口
|
||||||
|
func (p *PortDiscoveryService) discoverAlivePorts(hosts []string) []string {
|
||||||
|
var alivePorts []string
|
||||||
|
|
||||||
|
// 根据扫描模式选择端口扫描方式
|
||||||
|
if len(hosts) > 0 {
|
||||||
|
alivePorts = EnhancedPortScan(hosts, common.Ports, common.Timeout)
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并额外指定的端口
|
||||||
|
if len(common.HostPort) > 0 {
|
||||||
|
alivePorts = append(alivePorts, common.HostPort...)
|
||||||
|
alivePorts = common.RemoveDuplicate(alivePorts)
|
||||||
|
common.HostPort = nil
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return alivePorts
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertToTargetInfos 将端口列表转换为目标信息
|
||||||
|
func (p *PortDiscoveryService) convertToTargetInfos(ports []string, baseInfo common.HostInfo) []common.HostInfo {
|
||||||
|
var infos []common.HostInfo
|
||||||
|
|
||||||
|
for _, targetIP := range ports {
|
||||||
|
hostParts := strings.Split(targetIP, ":")
|
||||||
|
if len(hostParts) != 2 {
|
||||||
|
common.LogError(i18n.GetText("parse_error_invalid_target_format", targetIP))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
info := baseInfo
|
||||||
|
info.Host = hostParts[0]
|
||||||
|
info.Ports = hostParts[1]
|
||||||
|
infos = append(infos, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
return infos
|
||||||
|
}
|
162
Core/Scanner.go
162
Core/Scanner.go
@ -6,81 +6,63 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/common/i18n"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
"github.com/shadow1ng/fscan/webscan/lib"
|
"github.com/shadow1ng/fscan/webscan/lib"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ScanTask 表示单个扫描任务
|
|
||||||
type ScanTask struct {
|
|
||||||
pluginName string // 插件名称
|
|
||||||
target common.HostInfo // 目标信息
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScanStrategy 定义扫描策略接口
|
// ScanStrategy 定义扫描策略接口(简化版)
|
||||||
type ScanStrategy interface {
|
type ScanStrategy interface {
|
||||||
// 名称和描述
|
|
||||||
Name() string
|
|
||||||
Description() string
|
|
||||||
|
|
||||||
// 执行扫描的主要方法
|
// 执行扫描的主要方法
|
||||||
Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup)
|
Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup)
|
||||||
|
|
||||||
// 插件管理方法
|
// 插件管理方法
|
||||||
GetPlugins() ([]string, bool)
|
GetPlugins() ([]string, bool)
|
||||||
LogPluginInfo()
|
|
||||||
|
|
||||||
// 任务准备方法
|
|
||||||
PrepareTargets(info common.HostInfo) []common.HostInfo
|
|
||||||
IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool
|
IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scanner 扫描器结构体
|
|
||||||
type Scanner struct {
|
|
||||||
strategy ScanStrategy
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewScanner 创建新的扫描器并选择合适的策略
|
|
||||||
func NewScanner(info common.HostInfo) *Scanner {
|
|
||||||
scanner := &Scanner{}
|
|
||||||
scanner.selectStrategy(info)
|
|
||||||
return scanner
|
|
||||||
}
|
|
||||||
|
|
||||||
// selectStrategy 根据扫描配置选择适当的扫描策略
|
// selectStrategy 根据扫描配置选择适当的扫描策略
|
||||||
func (s *Scanner) selectStrategy(info common.HostInfo) {
|
func selectStrategy(info common.HostInfo) ScanStrategy {
|
||||||
switch {
|
switch {
|
||||||
|
case common.AliveOnly || common.ScanMode == "icmp":
|
||||||
|
common.LogBase(i18n.GetText("scan_mode_alive_selected"))
|
||||||
|
return NewAliveScanStrategy()
|
||||||
case common.LocalMode:
|
case common.LocalMode:
|
||||||
s.strategy = NewLocalScanStrategy()
|
common.LogBase(i18n.GetText("scan_mode_local_selected"))
|
||||||
common.LogBase("已选择本地扫描模式")
|
return NewLocalScanStrategy()
|
||||||
case len(common.URLs) > 0:
|
case len(common.URLs) > 0:
|
||||||
s.strategy = NewWebScanStrategy()
|
common.LogBase(i18n.GetText("scan_mode_web_selected"))
|
||||||
common.LogBase("已选择Web扫描模式")
|
return NewWebScanStrategy()
|
||||||
default:
|
default:
|
||||||
s.strategy = NewServiceScanStrategy()
|
|
||||||
common.LogBase(i18n.GetText("scan_mode_service_selected"))
|
common.LogBase(i18n.GetText("scan_mode_service_selected"))
|
||||||
|
return NewServiceScanStrategy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan 执行整体扫描流程
|
// RunScan 执行整体扫描流程(简化版,移除不必要的包装)
|
||||||
func (s *Scanner) Scan(info common.HostInfo) {
|
func RunScan(info common.HostInfo) {
|
||||||
common.LogBase(i18n.GetText("scan_info_start"))
|
common.LogBase(i18n.GetText("scan_info_start"))
|
||||||
lib.Inithttp()
|
lib.Inithttp()
|
||||||
|
|
||||||
|
// 选择策略
|
||||||
|
strategy := selectStrategy(info)
|
||||||
|
|
||||||
// 并发控制初始化
|
// 并发控制初始化
|
||||||
ch := make(chan struct{}, common.ThreadNum)
|
ch := make(chan struct{}, common.ThreadNum)
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
|
|
||||||
// 执行策略
|
// 执行策略
|
||||||
s.strategy.Execute(info, &ch, &wg)
|
strategy.Execute(info, &ch, &wg)
|
||||||
|
|
||||||
// 等待所有扫描完成
|
// 等待所有扫描完成
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
s.finishScan()
|
|
||||||
|
// 完成扫描
|
||||||
|
finishScan()
|
||||||
}
|
}
|
||||||
|
|
||||||
// finishScan 完成扫描并输出结果
|
// finishScan 完成扫描并输出结果
|
||||||
func (s *Scanner) finishScan() {
|
func finishScan() {
|
||||||
// 确保进度条正确完成
|
// 确保进度条正确完成
|
||||||
if common.IsProgressActive() {
|
if common.IsProgressActive() {
|
||||||
common.FinishProgressBar()
|
common.FinishProgressBar()
|
||||||
@ -90,31 +72,21 @@ func (s *Scanner) finishScan() {
|
|||||||
common.LogBase(i18n.GetText("scan_task_complete", common.End, common.Num))
|
common.LogBase(i18n.GetText("scan_task_complete", common.End, common.Num))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 任务执行通用框架
|
// ExecuteScanTasks 任务执行通用框架(流式处理,无预构建任务列表)
|
||||||
func ExecuteScanTasks(targets []common.HostInfo, strategy ScanStrategy, ch *chan struct{}, wg *sync.WaitGroup) {
|
func ExecuteScanTasks(targets []common.HostInfo, strategy ScanStrategy, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
// 获取要执行的插件
|
// 获取要执行的插件
|
||||||
pluginsToRun, isCustomMode := strategy.GetPlugins()
|
pluginsToRun, isCustomMode := strategy.GetPlugins()
|
||||||
|
|
||||||
// 准备扫描任务
|
// 预计算任务数量用于进度条
|
||||||
tasks := prepareScanTasks(targets, pluginsToRun, isCustomMode, strategy)
|
taskCount := countApplicableTasks(targets, pluginsToRun, isCustomMode, strategy)
|
||||||
|
|
||||||
|
|
||||||
// 初始化进度条
|
// 初始化进度条
|
||||||
if len(tasks) > 0 && common.ShowProgress {
|
if taskCount > 0 && common.ShowProgress {
|
||||||
description := i18n.GetText("progress_scanning_description")
|
description := i18n.GetText("progress_scanning_description")
|
||||||
common.InitProgressBar(int64(len(tasks)), description)
|
common.InitProgressBar(int64(taskCount), description)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行所有任务
|
// 流式执行任务,避免预构建大量任务对象
|
||||||
for _, task := range tasks {
|
|
||||||
scheduleScanTask(task.pluginName, task.target, ch, wg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 准备扫描任务列表
|
|
||||||
func prepareScanTasks(targets []common.HostInfo, pluginsToRun []string, isCustomMode bool, strategy ScanStrategy) []ScanTask {
|
|
||||||
var tasks []ScanTask
|
|
||||||
|
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
targetPort := 0
|
targetPort := 0
|
||||||
if target.Ports != "" {
|
if target.Ports != "" {
|
||||||
@ -127,40 +99,36 @@ func prepareScanTasks(targets []common.HostInfo, pluginsToRun []string, isCustom
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查插件是否适用于当前目标 (通过策略判断)
|
// 检查插件是否适用于当前目标
|
||||||
if strategy.IsPluginApplicable(plugin, targetPort, isCustomMode) {
|
if strategy.IsPluginApplicable(plugin, targetPort, isCustomMode) {
|
||||||
tasks = append(tasks, ScanTask{
|
executeScanTask(pluginName, target, ch, wg)
|
||||||
pluginName: pluginName,
|
|
||||||
target: target,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tasks
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// logScanPlan 输出扫描计划信息
|
// countApplicableTasks 计算适用的任务数量(用于进度条初始化)
|
||||||
func logScanPlan(tasks []ScanTask) {
|
func countApplicableTasks(targets []common.HostInfo, pluginsToRun []string, isCustomMode bool, strategy ScanStrategy) int {
|
||||||
// 统计每个插件的目标数量
|
count := 0
|
||||||
pluginCounts := make(map[string]int)
|
for _, target := range targets {
|
||||||
for _, task := range tasks {
|
targetPort := 0
|
||||||
pluginCounts[task.pluginName]++
|
if target.Ports != "" {
|
||||||
|
targetPort, _ = strconv.Atoi(target.Ports)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pluginName := range pluginsToRun {
|
||||||
|
plugin, exists := common.PluginManager[pluginName]
|
||||||
|
if exists && strategy.IsPluginApplicable(plugin, targetPort, isCustomMode) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return count
|
||||||
// 构建扫描计划信息
|
|
||||||
var planInfo strings.Builder
|
|
||||||
planInfo.WriteString("扫描计划:\n")
|
|
||||||
|
|
||||||
for plugin, count := range pluginCounts {
|
|
||||||
planInfo.WriteString(fmt.Sprintf(" - %s: %d 个目标\n", plugin, count))
|
|
||||||
}
|
|
||||||
|
|
||||||
common.LogBase(planInfo.String())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调度单个扫描任务
|
|
||||||
func scheduleScanTask(pluginName string, target common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
// executeScanTask 执行单个扫描任务(合并原 scheduleScanTask 和 executeSingleScan)
|
||||||
|
func executeScanTask(pluginName string, target common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
*ch <- struct{}{} // 获取并发槽位
|
*ch <- struct{}{} // 获取并发槽位
|
||||||
|
|
||||||
@ -168,38 +136,34 @@ func scheduleScanTask(pluginName string, target common.HostInfo, ch *chan struct
|
|||||||
defer func() {
|
defer func() {
|
||||||
// 捕获并记录任何可能的panic
|
// 捕获并记录任何可能的panic
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
common.LogError(fmt.Sprintf("[PANIC] 插件 %s 扫描 %s:%s 时崩溃: %v",
|
common.LogError(fmt.Sprintf(i18n.GetText("scan_plugin_panic"),
|
||||||
pluginName, target.Host, target.Ports, r))
|
pluginName, target.Host, target.Ports, r))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 完成任务,释放资源
|
// 完成任务,释放资源
|
||||||
|
|
||||||
wg.Done()
|
wg.Done()
|
||||||
<-*ch // 释放并发槽位
|
<-*ch // 释放并发槽位
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// 更新统计和进度
|
||||||
atomic.AddInt64(&common.Num, 1)
|
atomic.AddInt64(&common.Num, 1)
|
||||||
executeSingleScan(pluginName, target)
|
|
||||||
common.UpdateProgressBar(1)
|
common.UpdateProgressBar(1)
|
||||||
|
|
||||||
|
// 执行扫描
|
||||||
|
plugin, exists := common.PluginManager[pluginName]
|
||||||
|
if !exists {
|
||||||
|
common.LogBase(fmt.Sprintf(i18n.GetText("scan_plugin_not_found"), pluginName))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := plugin.ScanFunc(&target); err != nil {
|
||||||
|
common.LogError(fmt.Sprintf(i18n.GetText("scan_plugin_error"), target.Host, target.Ports, err))
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行单个扫描
|
|
||||||
func executeSingleScan(pluginName string, info common.HostInfo) {
|
|
||||||
plugin, exists := common.PluginManager[pluginName]
|
|
||||||
if !exists {
|
|
||||||
common.LogBase(fmt.Sprintf("扫描类型 %v 无对应插件,已跳过", pluginName))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := plugin.ScanFunc(&info); err != nil {
|
// Scan 入口函数,向后兼容旧的调用方式
|
||||||
common.LogError(fmt.Sprintf("扫描错误 %v:%v - %v", info.Host, info.Ports, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 入口函数,向后兼容旧的调用方式
|
|
||||||
func Scan(info common.HostInfo) {
|
func Scan(info common.HostInfo) {
|
||||||
scanner := NewScanner(info)
|
RunScan(info)
|
||||||
scanner.Scan(info)
|
|
||||||
}
|
}
|
||||||
|
@ -1,80 +1,70 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
"github.com/shadow1ng/fscan/common/parsers"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServiceScanStrategy 服务扫描策略
|
// ServiceScanStrategy 服务扫描策略
|
||||||
type ServiceScanStrategy struct{}
|
type ServiceScanStrategy struct {
|
||||||
|
*BaseScanStrategy
|
||||||
|
portDiscovery *PortDiscoveryService
|
||||||
|
}
|
||||||
|
|
||||||
// NewServiceScanStrategy 创建新的服务扫描策略
|
// NewServiceScanStrategy 创建新的服务扫描策略
|
||||||
func NewServiceScanStrategy() *ServiceScanStrategy {
|
func NewServiceScanStrategy() *ServiceScanStrategy {
|
||||||
return &ServiceScanStrategy{}
|
return &ServiceScanStrategy{
|
||||||
|
BaseScanStrategy: NewBaseScanStrategy("服务扫描", FilterService),
|
||||||
|
portDiscovery: NewPortDiscoveryService(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name 返回策略名称
|
// Name 返回策略名称
|
||||||
func (s *ServiceScanStrategy) Name() string {
|
func (s *ServiceScanStrategy) Name() string {
|
||||||
return "服务扫描"
|
return i18n.GetText("scan_strategy_service_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description 返回策略描述
|
// Description 返回策略描述
|
||||||
func (s *ServiceScanStrategy) Description() string {
|
func (s *ServiceScanStrategy) Description() string {
|
||||||
return "扫描主机服务和漏洞"
|
return i18n.GetText("scan_strategy_service_desc")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute 执行服务扫描策略
|
// Execute 执行服务扫描策略
|
||||||
func (s *ServiceScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func (s *ServiceScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
// 验证扫描目标
|
// 验证扫描目标
|
||||||
if info.Host == "" {
|
if info.Host == "" {
|
||||||
common.LogError("未指定扫描目标")
|
common.LogError(i18n.GetText("parse_error_target_empty"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 输出扫描开始信息
|
||||||
|
s.LogScanStart()
|
||||||
|
|
||||||
// 验证插件配置
|
// 验证插件配置
|
||||||
if err := validateScanPlugins(); err != nil {
|
if err := s.ValidateConfiguration(); err != nil {
|
||||||
common.LogError(err.Error())
|
common.LogError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析目标主机
|
|
||||||
hosts, err := parsers.ParseIP(info.Host, common.HostsFile, common.ExcludeHosts)
|
|
||||||
if err != nil {
|
|
||||||
common.LogError(fmt.Sprintf("解析主机错误: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
common.LogBase(i18n.GetText("scan_host_start"))
|
common.LogBase(i18n.GetText("scan_host_start"))
|
||||||
|
|
||||||
// 输出插件信息
|
// 输出插件信息
|
||||||
s.LogPluginInfo()
|
s.LogPluginInfo()
|
||||||
|
|
||||||
// 执行主机扫描流程
|
// 执行主机扫描流程
|
||||||
s.performHostScan(hosts, info, ch, wg)
|
s.performHostScan(info, ch, wg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// performHostScan 执行主机扫描的完整流程
|
// performHostScan 执行主机扫描的完整流程
|
||||||
func (s *ServiceScanStrategy) performHostScan(hosts []string, info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func (s *ServiceScanStrategy) performHostScan(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
var targetInfos []common.HostInfo
|
// 使用端口发现服务发现目标
|
||||||
|
targetInfos, err := s.portDiscovery.DiscoverTargets(info.Host, info)
|
||||||
// 主机存活性检测和端口扫描
|
if err != nil {
|
||||||
if len(hosts) > 0 || len(common.HostPort) > 0 {
|
common.LogError(err.Error())
|
||||||
// 主机存活检测
|
return
|
||||||
if s.shouldPerformLivenessCheck(hosts) {
|
|
||||||
hosts = CheckLive(hosts, false)
|
|
||||||
common.LogBase(fmt.Sprintf("存活主机数量: %d", len(hosts)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 端口扫描
|
|
||||||
alivePorts := s.discoverAlivePorts(hosts)
|
|
||||||
if len(alivePorts) > 0 {
|
|
||||||
targetInfos = s.convertToTargetInfos(alivePorts, info)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行漏洞扫描
|
// 执行漏洞扫描
|
||||||
@ -86,161 +76,55 @@ func (s *ServiceScanStrategy) performHostScan(hosts []string, info common.HostIn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shouldPerformLivenessCheck 判断是否需要执行存活性检测
|
|
||||||
func (s *ServiceScanStrategy) shouldPerformLivenessCheck(hosts []string) bool {
|
|
||||||
return common.DisablePing == false && len(hosts) > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// discoverAlivePorts 发现存活的端口
|
|
||||||
func (s *ServiceScanStrategy) discoverAlivePorts(hosts []string) []string {
|
|
||||||
var alivePorts []string
|
|
||||||
|
|
||||||
// 根据扫描模式选择端口扫描方式
|
|
||||||
if len(hosts) > 0 {
|
|
||||||
alivePorts = EnhancedPortScan(hosts, common.Ports, common.Timeout)
|
|
||||||
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 合并额外指定的端口
|
|
||||||
if len(common.HostPort) > 0 {
|
|
||||||
alivePorts = append(alivePorts, common.HostPort...)
|
|
||||||
alivePorts = common.RemoveDuplicate(alivePorts)
|
|
||||||
common.HostPort = nil
|
|
||||||
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
|
|
||||||
}
|
|
||||||
|
|
||||||
return alivePorts
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrepareTargets 准备目标信息
|
// PrepareTargets 准备目标信息
|
||||||
func (s *ServiceScanStrategy) PrepareTargets(info common.HostInfo) []common.HostInfo {
|
func (s *ServiceScanStrategy) PrepareTargets(info common.HostInfo) []common.HostInfo {
|
||||||
// 解析目标主机
|
// 使用端口发现服务发现目标
|
||||||
hosts, err := parsers.ParseIP(info.Host, common.HostsFile, common.ExcludeHosts)
|
targetInfos, err := s.portDiscovery.DiscoverTargets(info.Host, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.LogError(fmt.Sprintf("解析主机错误: %v", err))
|
common.LogError(err.Error())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetInfos []common.HostInfo
|
|
||||||
|
|
||||||
// 主机存活性检测和端口扫描
|
|
||||||
if len(hosts) > 0 || len(common.HostPort) > 0 {
|
|
||||||
// 主机存活检测
|
|
||||||
if s.shouldPerformLivenessCheck(hosts) {
|
|
||||||
hosts = CheckLive(hosts, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 端口扫描
|
|
||||||
alivePorts := s.discoverAlivePorts(hosts)
|
|
||||||
if len(alivePorts) > 0 {
|
|
||||||
targetInfos = s.convertToTargetInfos(alivePorts, info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetInfos
|
return targetInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertToTargetInfos 将端口列表转换为目标信息
|
|
||||||
func (s *ServiceScanStrategy) convertToTargetInfos(ports []string, baseInfo common.HostInfo) []common.HostInfo {
|
|
||||||
var infos []common.HostInfo
|
|
||||||
|
|
||||||
for _, targetIP := range ports {
|
|
||||||
hostParts := strings.Split(targetIP, ":")
|
|
||||||
if len(hostParts) != 2 {
|
|
||||||
common.LogError(fmt.Sprintf("无效的目标地址格式: %s", targetIP))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
info := baseInfo
|
|
||||||
info.Host = hostParts[0]
|
|
||||||
info.Ports = hostParts[1]
|
|
||||||
infos = append(infos, info)
|
|
||||||
}
|
|
||||||
|
|
||||||
return infos
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPlugins 获取服务扫描插件列表
|
|
||||||
func (s *ServiceScanStrategy) GetPlugins() ([]string, bool) {
|
|
||||||
// 如果指定了插件列表且不是"all"
|
|
||||||
if common.ScanMode != "" && common.ScanMode != "all" {
|
|
||||||
plugins := parsePluginList(common.ScanMode)
|
|
||||||
if len(plugins) > 0 {
|
|
||||||
return plugins, true
|
|
||||||
}
|
|
||||||
return []string{common.ScanMode}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未指定或使用"all":获取所有插件,由IsPluginApplicable做类型过滤
|
|
||||||
return GetAllPlugins(), false
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogPluginInfo 输出服务扫描插件信息
|
|
||||||
func (s *ServiceScanStrategy) LogPluginInfo() {
|
|
||||||
allPlugins, isCustomMode := s.GetPlugins()
|
|
||||||
|
|
||||||
// 如果是自定义模式,直接显示用户指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
common.LogBase(fmt.Sprintf("使用指定插件: %s", strings.Join(allPlugins, ", ")))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在自动模式下,过滤掉本地插件,只显示服务类型插件
|
|
||||||
var applicablePlugins []string
|
|
||||||
for _, pluginName := range allPlugins {
|
|
||||||
plugin, exists := common.PluginManager[pluginName]
|
|
||||||
if exists && !plugin.HasType(common.PluginTypeLocal) {
|
|
||||||
applicablePlugins = append(applicablePlugins, pluginName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(applicablePlugins) > 0 {
|
|
||||||
common.LogBase(fmt.Sprintf("使用服务插件: %s", strings.Join(applicablePlugins, ", ")))
|
|
||||||
} else {
|
|
||||||
common.LogBase(i18n.GetText("scan_no_service_plugins"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogVulnerabilityPluginInfo 输出漏洞扫描插件信息
|
// LogVulnerabilityPluginInfo 输出漏洞扫描插件信息
|
||||||
func (s *ServiceScanStrategy) LogVulnerabilityPluginInfo(targets []common.HostInfo) {
|
func (s *ServiceScanStrategy) LogVulnerabilityPluginInfo(targets []common.HostInfo) {
|
||||||
allPlugins, isCustomMode := s.GetPlugins()
|
allPlugins, isCustomMode := s.GetPlugins()
|
||||||
|
|
||||||
// 获取实际会被使用的插件列表
|
// 收集所有目标端口用于插件适用性检查
|
||||||
var vulnerabilityPlugins []string
|
portSet := make(map[int]bool)
|
||||||
pluginUsed := make(map[string]bool)
|
|
||||||
|
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
targetPort := 0
|
|
||||||
if target.Ports != "" {
|
if target.Ports != "" {
|
||||||
targetPort, _ = strconv.Atoi(target.Ports)
|
if port, err := strconv.Atoi(target.Ports); err == nil {
|
||||||
|
portSet[port] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取实际会被使用的插件列表(优化版本)
|
||||||
|
var vulnerabilityPlugins []string
|
||||||
|
for _, pluginName := range allPlugins {
|
||||||
|
plugin, exists := common.PluginManager[pluginName]
|
||||||
|
if !exists {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pluginName := range allPlugins {
|
// 检查插件是否对任何目标端口适用
|
||||||
plugin, exists := common.PluginManager[pluginName]
|
if s.isPluginApplicableToAnyPort(plugin, portSet, isCustomMode) {
|
||||||
if !exists {
|
vulnerabilityPlugins = append(vulnerabilityPlugins, pluginName)
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查插件是否适用于当前目标(使用与ExecuteScanTasks相同的逻辑)
|
|
||||||
if s.IsPluginApplicable(plugin, targetPort, isCustomMode) {
|
|
||||||
if !pluginUsed[pluginName] {
|
|
||||||
vulnerabilityPlugins = append(vulnerabilityPlugins, pluginName)
|
|
||||||
pluginUsed[pluginName] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 输出插件信息
|
// 输出插件信息
|
||||||
if len(vulnerabilityPlugins) > 0 {
|
if len(vulnerabilityPlugins) > 0 {
|
||||||
common.LogBase(fmt.Sprintf(i18n.GetText("scan_vulnerability_plugins"), strings.Join(vulnerabilityPlugins, ", ")))
|
common.LogBase(i18n.GetText("scan_vulnerability_plugins", strings.Join(vulnerabilityPlugins, ", ")))
|
||||||
} else {
|
} else {
|
||||||
common.LogBase(i18n.GetText("scan_no_vulnerability_plugins"))
|
common.LogBase(i18n.GetText("scan_no_vulnerability_plugins"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPluginApplicable 判断插件是否适用于服务扫描
|
// isPluginApplicableToAnyPort 检查插件是否对任何端口适用(性能优化)
|
||||||
func (s *ServiceScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
func (s *ServiceScanStrategy) isPluginApplicableToAnyPort(plugin common.ScanPlugin, portSet map[int]bool, isCustomMode bool) bool {
|
||||||
// 自定义模式下运行所有明确指定的插件
|
// 自定义模式下运行所有明确指定的插件
|
||||||
if isCustomMode {
|
if isCustomMode {
|
||||||
return true
|
return true
|
||||||
@ -251,11 +135,17 @@ func (s *ServiceScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targe
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查端口是否匹配
|
// 无端口限制的插件适用于所有端口
|
||||||
if len(plugin.Ports) > 0 && targetPort > 0 {
|
if len(plugin.Ports) == 0 {
|
||||||
return plugin.HasPort(targetPort)
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 无端口限制的插件或适用于服务扫描的插件
|
// 有端口限制的插件:检查是否匹配任何目标端口
|
||||||
return len(plugin.Ports) == 0 || plugin.HasType(common.PluginTypeService)
|
for port := range portSet {
|
||||||
|
if plugin.HasPort(port) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,41 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WebScanStrategy Web扫描策略
|
// WebScanStrategy Web扫描策略
|
||||||
type WebScanStrategy struct{}
|
type WebScanStrategy struct {
|
||||||
|
*BaseScanStrategy
|
||||||
|
}
|
||||||
|
|
||||||
// NewWebScanStrategy 创建新的Web扫描策略
|
// NewWebScanStrategy 创建新的Web扫描策略
|
||||||
func NewWebScanStrategy() *WebScanStrategy {
|
func NewWebScanStrategy() *WebScanStrategy {
|
||||||
return &WebScanStrategy{}
|
return &WebScanStrategy{
|
||||||
|
BaseScanStrategy: NewBaseScanStrategy("Web扫描", FilterWeb),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name 返回策略名称
|
// Name 返回策略名称
|
||||||
func (s *WebScanStrategy) Name() string {
|
func (s *WebScanStrategy) Name() string {
|
||||||
return "Web扫描"
|
return i18n.GetText("scan_strategy_web_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description 返回策略描述
|
// Description 返回策略描述
|
||||||
func (s *WebScanStrategy) Description() string {
|
func (s *WebScanStrategy) Description() string {
|
||||||
return "扫描Web应用漏洞和信息"
|
return i18n.GetText("scan_strategy_web_desc")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute 执行Web扫描策略
|
// Execute 执行Web扫描策略
|
||||||
func (s *WebScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func (s *WebScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
common.LogBase("开始Web扫描")
|
// 输出扫描开始信息
|
||||||
|
s.LogScanStart()
|
||||||
|
|
||||||
// 验证插件配置
|
// 验证插件配置
|
||||||
if err := validateScanPlugins(); err != nil {
|
if err := s.ValidateConfiguration(); err != nil {
|
||||||
common.LogError(err.Error())
|
common.LogError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -62,64 +67,3 @@ func (s *WebScanStrategy) PrepareTargets(baseInfo common.HostInfo) []common.Host
|
|||||||
return targetInfos
|
return targetInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlugins 获取Web扫描插件列表
|
|
||||||
func (s *WebScanStrategy) GetPlugins() ([]string, bool) {
|
|
||||||
// 如果指定了自定义插件并且不是"all"
|
|
||||||
if common.ScanMode != "" && common.ScanMode != "all" {
|
|
||||||
requestedPlugins := parsePluginList(common.ScanMode)
|
|
||||||
if len(requestedPlugins) == 0 {
|
|
||||||
requestedPlugins = []string{common.ScanMode}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证插件是否存在,不做Web类型过滤
|
|
||||||
var validPlugins []string
|
|
||||||
for _, name := range requestedPlugins {
|
|
||||||
if _, exists := common.PluginManager[name]; exists {
|
|
||||||
validPlugins = append(validPlugins, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(validPlugins) > 0 {
|
|
||||||
return validPlugins, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未指定或使用"all":获取所有插件,由IsPluginApplicable做类型过滤
|
|
||||||
return GetAllPlugins(), false
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogPluginInfo 输出Web扫描插件信息
|
|
||||||
func (s *WebScanStrategy) LogPluginInfo() {
|
|
||||||
allPlugins, isCustomMode := s.GetPlugins()
|
|
||||||
|
|
||||||
// 如果是自定义模式,直接显示用户指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
common.LogBase(fmt.Sprintf("Web扫描模式: 使用指定插件: %s", strings.Join(allPlugins, ", ")))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在自动模式下,只显示Web类型的插件
|
|
||||||
var applicablePlugins []string
|
|
||||||
for _, pluginName := range allPlugins {
|
|
||||||
plugin, exists := common.PluginManager[pluginName]
|
|
||||||
if exists && plugin.HasType(common.PluginTypeWeb) {
|
|
||||||
applicablePlugins = append(applicablePlugins, pluginName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(applicablePlugins) > 0 {
|
|
||||||
common.LogBase(fmt.Sprintf("Web扫描模式: 使用Web插件: %s", strings.Join(applicablePlugins, ", ")))
|
|
||||||
} else {
|
|
||||||
common.LogBase("Web扫描模式: 未找到可用的Web插件")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPluginApplicable 判断插件是否适用于Web扫描
|
|
||||||
func (s *WebScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
|
||||||
// 自定义模式下运行所有明确指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// 非自定义模式下,只运行Web类型插件
|
|
||||||
return plugin.HasType(common.PluginTypeWeb)
|
|
||||||
}
|
|
||||||
|
@ -3,7 +3,6 @@ package portfinger
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
@ -95,49 +94,6 @@ func (p *Probe) getSoftMatch(data string) (softMatch Match, err error) {
|
|||||||
return softMatch, nil
|
return softMatch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// containsPort 检查指定端口是否在探测器的端口范围内(私有方法)
|
|
||||||
func (p *Probe) containsPort(testPort int) bool {
|
|
||||||
common.LogDebug(fmt.Sprintf("检查端口 %d 是否在探测器端口范围内: %s", testPort, p.Ports))
|
|
||||||
|
|
||||||
// 检查单个端口
|
|
||||||
ports := strings.Split(p.Ports, ",")
|
|
||||||
for _, port := range ports {
|
|
||||||
port = strings.TrimSpace(port)
|
|
||||||
cmpPort, err := strconv.Atoi(port)
|
|
||||||
if err == nil && testPort == cmpPort {
|
|
||||||
common.LogDebug(fmt.Sprintf("端口 %d 匹配单个端口", testPort))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查端口范围
|
|
||||||
for _, port := range ports {
|
|
||||||
port = strings.TrimSpace(port)
|
|
||||||
if strings.Contains(port, "-") {
|
|
||||||
portRange := strings.Split(port, "-")
|
|
||||||
if len(portRange) != 2 {
|
|
||||||
common.LogDebug("无效的端口范围格式: " + port)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
start, err1 := strconv.Atoi(strings.TrimSpace(portRange[0]))
|
|
||||||
end, err2 := strconv.Atoi(strings.TrimSpace(portRange[1]))
|
|
||||||
|
|
||||||
if err1 != nil || err2 != nil {
|
|
||||||
common.LogDebug(fmt.Sprintf("解析端口范围失败: %s", port))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if testPort >= start && testPort <= end {
|
|
||||||
common.LogDebug(fmt.Sprintf("端口 %d 在范围 %d-%d 内", testPort, start, end))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
common.LogDebug(fmt.Sprintf("端口 %d 不在探测器端口范围内", testPort))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchPattern 检查响应是否与匹配规则匹配
|
// MatchPattern 检查响应是否与匹配规则匹配
|
||||||
func (m *Match) MatchPattern(response []byte) bool {
|
func (m *Match) MatchPattern(response []byte) bool {
|
||||||
@ -161,13 +117,4 @@ func (m *Match) MatchPattern(response []byte) bool {
|
|||||||
return matched
|
return matched
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPortMatch 检查探测器是否适用于指定端口
|
|
||||||
func (p *Probe) IsPortMatch(port int) bool {
|
|
||||||
// 如果没有指定端口范围,认为适用于所有端口
|
|
||||||
if p.Ports == "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.containsPort(port)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user