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

主要改进: - 模块化设计:将549行Parse.go拆分为6个专用解析器 - 性能优化:添加文件缓存、并发处理和去重机制 - 增强验证:实现配置冲突检测和参数验证 - 改善体验:清理冗余警告,添加解析结果摘要显示 - 向后兼容:保持所有原有API接口不变 新增模块: - FileReader: 高性能文件读取和缓存 - CredentialParser: 用户名密码解析 - TargetParser: 主机目标解析 - NetworkParser: 网络配置解析 - ValidationParser: 参数验证和冲突检测 - Types: 统一的数据结构定义 修复问题: - 消除重复的"Web超时时间大于普通超时时间"警告 - 添加目标主机、端口、代理等配置信息显示 - 删除说教性安全警告,保留技术性提示
712 lines
18 KiB
Go
712 lines
18 KiB
Go
package parsers
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// TargetParser 目标解析器
|
|
type TargetParser struct {
|
|
fileReader *FileReader
|
|
mu sync.RWMutex
|
|
ipRegex *regexp.Regexp
|
|
portRegex *regexp.Regexp
|
|
urlRegex *regexp.Regexp
|
|
options *TargetParserOptions
|
|
}
|
|
|
|
// TargetParserOptions 目标解析器选项
|
|
type TargetParserOptions struct {
|
|
MaxTargets int `json:"max_targets"`
|
|
MaxPortRange int `json:"max_port_range"`
|
|
AllowPrivateIPs bool `json:"allow_private_ips"`
|
|
AllowLoopback bool `json:"allow_loopback"`
|
|
ValidateURLs bool `json:"validate_urls"`
|
|
ResolveDomains bool `json:"resolve_domains"`
|
|
EnableStatistics bool `json:"enable_statistics"`
|
|
DefaultPorts string `json:"default_ports"`
|
|
}
|
|
|
|
// DefaultTargetParserOptions 默认目标解析器选项
|
|
func DefaultTargetParserOptions() *TargetParserOptions {
|
|
return &TargetParserOptions{
|
|
MaxTargets: 10000,
|
|
MaxPortRange: 1000,
|
|
AllowPrivateIPs: true,
|
|
AllowLoopback: true,
|
|
ValidateURLs: true,
|
|
ResolveDomains: false,
|
|
EnableStatistics: true,
|
|
DefaultPorts: "80,443,22,21,23,25,53,110,993,995,1433,3306,5432,6379,27017",
|
|
}
|
|
}
|
|
|
|
// NewTargetParser 创建目标解析器
|
|
func NewTargetParser(fileReader *FileReader, options *TargetParserOptions) *TargetParser {
|
|
if options == nil {
|
|
options = DefaultTargetParserOptions()
|
|
}
|
|
|
|
// 编译正则表达式
|
|
ipRegex := regexp.MustCompile(`^(\d{1,3}\.){3}\d{1,3}$`)
|
|
portRegex := regexp.MustCompile(`^(\d+)(-(\d+))?$`)
|
|
urlRegex := regexp.MustCompile(`^https?://[^\s/$.?#].[^\s]*$`)
|
|
|
|
return &TargetParser{
|
|
fileReader: fileReader,
|
|
ipRegex: ipRegex,
|
|
portRegex: portRegex,
|
|
urlRegex: urlRegex,
|
|
options: options,
|
|
}
|
|
}
|
|
|
|
// TargetInput 目标输入参数
|
|
type TargetInput struct {
|
|
// 主机相关
|
|
Host string `json:"host"`
|
|
HostsFile string `json:"hosts_file"`
|
|
ExcludeHosts string `json:"exclude_hosts"`
|
|
|
|
// 端口相关
|
|
Ports string `json:"ports"`
|
|
PortsFile string `json:"ports_file"`
|
|
AddPorts string `json:"add_ports"`
|
|
ExcludePorts string `json:"exclude_ports"`
|
|
|
|
// URL相关
|
|
TargetURL string `json:"target_url"`
|
|
URLsFile string `json:"urls_file"`
|
|
|
|
// 主机端口组合
|
|
HostPort []string `json:"host_port"`
|
|
|
|
// 模式标识
|
|
LocalMode bool `json:"local_mode"`
|
|
}
|
|
|
|
// Parse 解析目标配置
|
|
func (tp *TargetParser) Parse(input *TargetInput, options *ParserOptions) (*ParseResult, error) {
|
|
if input == nil {
|
|
return nil, NewParseError("INPUT_ERROR", "目标输入为空", "", 0, ErrEmptyInput)
|
|
}
|
|
|
|
startTime := time.Now()
|
|
result := &ParseResult{
|
|
Config: &ParsedConfig{
|
|
Targets: &TargetConfig{
|
|
LocalMode: input.LocalMode,
|
|
},
|
|
},
|
|
Success: true,
|
|
}
|
|
|
|
var errors []error
|
|
var warnings []string
|
|
|
|
// 解析主机
|
|
hosts, hostErrors, hostWarnings := tp.parseHosts(input)
|
|
errors = append(errors, hostErrors...)
|
|
warnings = append(warnings, hostWarnings...)
|
|
|
|
// 解析URL
|
|
urls, urlErrors, urlWarnings := tp.parseURLs(input)
|
|
errors = append(errors, urlErrors...)
|
|
warnings = append(warnings, urlWarnings...)
|
|
|
|
// 解析端口
|
|
ports, portErrors, portWarnings := tp.parsePorts(input)
|
|
errors = append(errors, portErrors...)
|
|
warnings = append(warnings, portWarnings...)
|
|
|
|
// 解析排除端口
|
|
excludePorts, excludeErrors, excludeWarnings := tp.parseExcludePorts(input)
|
|
errors = append(errors, excludeErrors...)
|
|
warnings = append(warnings, excludeWarnings...)
|
|
|
|
// 解析主机端口组合
|
|
hostPorts, hpErrors, hpWarnings := tp.parseHostPorts(input)
|
|
errors = append(errors, hpErrors...)
|
|
warnings = append(warnings, hpWarnings...)
|
|
|
|
// 更新配置
|
|
result.Config.Targets.Hosts = hosts
|
|
result.Config.Targets.URLs = urls
|
|
result.Config.Targets.Ports = ports
|
|
result.Config.Targets.ExcludePorts = excludePorts
|
|
result.Config.Targets.HostPorts = hostPorts
|
|
|
|
// 生成统计信息
|
|
if tp.options.EnableStatistics {
|
|
result.Config.Targets.Statistics = tp.generateStatistics(hosts, urls, ports, excludePorts)
|
|
}
|
|
|
|
// 设置结果状态
|
|
result.Errors = errors
|
|
result.Warnings = warnings
|
|
result.ParseTime = time.Since(startTime)
|
|
result.Success = len(errors) == 0
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// parseHosts 解析主机
|
|
func (tp *TargetParser) parseHosts(input *TargetInput) ([]string, []error, []string) {
|
|
var hosts []string
|
|
var errors []error
|
|
var warnings []string
|
|
|
|
// 解析命令行主机
|
|
if input.Host != "" {
|
|
hostList, err := tp.parseHostList(input.Host)
|
|
if err != nil {
|
|
errors = append(errors, NewParseError("HOST_ERROR", err.Error(), "command line", 0, err))
|
|
} else {
|
|
hosts = append(hosts, hostList...)
|
|
}
|
|
}
|
|
|
|
// 从文件读取主机
|
|
if input.HostsFile != "" {
|
|
fileResult, err := tp.fileReader.ReadFile(input.HostsFile)
|
|
if err != nil {
|
|
errors = append(errors, NewParseError("FILE_ERROR", "读取主机文件失败", input.HostsFile, 0, err))
|
|
} else {
|
|
for i, line := range fileResult.Lines {
|
|
hostList, err := tp.parseHostList(line)
|
|
if err != nil {
|
|
warnings = append(warnings, fmt.Sprintf("主机文件第%d行解析失败: %s", i+1, err.Error()))
|
|
} else {
|
|
hosts = append(hosts, hostList...)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 处理排除主机
|
|
if input.ExcludeHosts != "" {
|
|
excludeList, err := tp.parseHostList(input.ExcludeHosts)
|
|
if err != nil {
|
|
warnings = append(warnings, fmt.Sprintf("排除主机解析失败: %s", err.Error()))
|
|
} else {
|
|
hosts = tp.excludeHosts(hosts, excludeList)
|
|
}
|
|
}
|
|
|
|
// 去重和验证
|
|
hosts = tp.removeDuplicateStrings(hosts)
|
|
validHosts := make([]string, 0, len(hosts))
|
|
|
|
for _, host := range hosts {
|
|
if valid, err := tp.validateHost(host); valid {
|
|
validHosts = append(validHosts, host)
|
|
} else if err != nil {
|
|
warnings = append(warnings, fmt.Sprintf("无效主机: %s - %s", host, err.Error()))
|
|
}
|
|
}
|
|
|
|
// 检查目标数量限制
|
|
if len(validHosts) > tp.options.MaxTargets {
|
|
warnings = append(warnings, fmt.Sprintf("主机数量超过限制,截取前%d个", tp.options.MaxTargets))
|
|
validHosts = validHosts[:tp.options.MaxTargets]
|
|
}
|
|
|
|
return validHosts, errors, warnings
|
|
}
|
|
|
|
// parseURLs 解析URL
|
|
func (tp *TargetParser) parseURLs(input *TargetInput) ([]string, []error, []string) {
|
|
var urls []string
|
|
var errors []error
|
|
var warnings []string
|
|
|
|
// 解析命令行URL
|
|
if input.TargetURL != "" {
|
|
urlList := strings.Split(input.TargetURL, ",")
|
|
for _, rawURL := range urlList {
|
|
rawURL = strings.TrimSpace(rawURL)
|
|
if rawURL != "" {
|
|
if valid, err := tp.validateURL(rawURL); valid {
|
|
urls = append(urls, rawURL)
|
|
} else {
|
|
warnings = append(warnings, fmt.Sprintf("无效URL: %s - %s", rawURL, err.Error()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 从文件读取URL
|
|
if input.URLsFile != "" {
|
|
fileResult, err := tp.fileReader.ReadFile(input.URLsFile)
|
|
if err != nil {
|
|
errors = append(errors, NewParseError("FILE_ERROR", "读取URL文件失败", input.URLsFile, 0, err))
|
|
} else {
|
|
for i, line := range fileResult.Lines {
|
|
if valid, err := tp.validateURL(line); valid {
|
|
urls = append(urls, line)
|
|
} else {
|
|
warnings = append(warnings, fmt.Sprintf("URL文件第%d行无效: %s", i+1, err.Error()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 去重
|
|
urls = tp.removeDuplicateStrings(urls)
|
|
|
|
return urls, errors, warnings
|
|
}
|
|
|
|
// parsePorts 解析端口
|
|
func (tp *TargetParser) parsePorts(input *TargetInput) ([]int, []error, []string) {
|
|
var ports []int
|
|
var errors []error
|
|
var warnings []string
|
|
|
|
// 解析命令行端口
|
|
if input.Ports != "" {
|
|
portList, err := tp.parsePortList(input.Ports)
|
|
if err != nil {
|
|
errors = append(errors, NewParseError("PORT_ERROR", err.Error(), "command line", 0, err))
|
|
} else {
|
|
ports = append(ports, portList...)
|
|
}
|
|
}
|
|
|
|
// 从文件读取端口
|
|
if input.PortsFile != "" {
|
|
fileResult, err := tp.fileReader.ReadFile(input.PortsFile)
|
|
if err != nil {
|
|
errors = append(errors, NewParseError("FILE_ERROR", "读取端口文件失败", input.PortsFile, 0, err))
|
|
} else {
|
|
for i, line := range fileResult.Lines {
|
|
portList, err := tp.parsePortList(line)
|
|
if err != nil {
|
|
warnings = append(warnings, fmt.Sprintf("端口文件第%d行解析失败: %s", i+1, err.Error()))
|
|
} else {
|
|
ports = append(ports, portList...)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 处理额外端口
|
|
if input.AddPorts != "" {
|
|
addPortList, err := tp.parsePortList(input.AddPorts)
|
|
if err != nil {
|
|
warnings = append(warnings, fmt.Sprintf("额外端口解析失败: %s", err.Error()))
|
|
} else {
|
|
ports = append(ports, addPortList...)
|
|
}
|
|
}
|
|
|
|
// 去重和排序
|
|
ports = tp.removeDuplicatePorts(ports)
|
|
|
|
return ports, errors, warnings
|
|
}
|
|
|
|
// parseExcludePorts 解析排除端口
|
|
func (tp *TargetParser) parseExcludePorts(input *TargetInput) ([]int, []error, []string) {
|
|
var excludePorts []int
|
|
var errors []error
|
|
var warnings []string
|
|
|
|
if input.ExcludePorts != "" {
|
|
portList, err := tp.parsePortList(input.ExcludePorts)
|
|
if err != nil {
|
|
errors = append(errors, NewParseError("EXCLUDE_PORT_ERROR", err.Error(), "command line", 0, err))
|
|
} else {
|
|
excludePorts = portList
|
|
}
|
|
}
|
|
|
|
return excludePorts, errors, warnings
|
|
}
|
|
|
|
// parseHostPorts 解析主机端口组合
|
|
func (tp *TargetParser) parseHostPorts(input *TargetInput) ([]string, []error, []string) {
|
|
var hostPorts []string
|
|
var errors []error
|
|
var warnings []string
|
|
|
|
for _, hp := range input.HostPort {
|
|
if hp != "" {
|
|
if valid, err := tp.validateHostPort(hp); valid {
|
|
hostPorts = append(hostPorts, hp)
|
|
} else {
|
|
warnings = append(warnings, fmt.Sprintf("无效主机端口组合: %s - %s", hp, err.Error()))
|
|
}
|
|
}
|
|
}
|
|
|
|
return hostPorts, errors, warnings
|
|
}
|
|
|
|
// parseHostList 解析主机列表
|
|
func (tp *TargetParser) parseHostList(hostStr string) ([]string, error) {
|
|
if hostStr == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
var hosts []string
|
|
hostItems := strings.Split(hostStr, ",")
|
|
|
|
for _, item := range hostItems {
|
|
item = strings.TrimSpace(item)
|
|
if item == "" {
|
|
continue
|
|
}
|
|
|
|
// 检查是否为IP范围或CIDR
|
|
if strings.Contains(item, "/") {
|
|
// CIDR表示法
|
|
cidrHosts, err := tp.parseCIDR(item)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("CIDR解析失败 %s: %v", item, err)
|
|
}
|
|
hosts = append(hosts, cidrHosts...)
|
|
} else if strings.Contains(item, "-") {
|
|
// IP范围表示法
|
|
rangeHosts, err := tp.parseIPRange(item)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("IP范围解析失败 %s: %v", item, err)
|
|
}
|
|
hosts = append(hosts, rangeHosts...)
|
|
} else {
|
|
// 单个IP或域名
|
|
hosts = append(hosts, item)
|
|
}
|
|
}
|
|
|
|
return hosts, nil
|
|
}
|
|
|
|
// parsePortList 解析端口列表
|
|
func (tp *TargetParser) parsePortList(portStr string) ([]int, error) {
|
|
if portStr == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
var ports []int
|
|
portItems := strings.Split(portStr, ",")
|
|
|
|
for _, item := range portItems {
|
|
item = strings.TrimSpace(item)
|
|
if item == "" {
|
|
continue
|
|
}
|
|
|
|
if strings.Contains(item, "-") {
|
|
// 端口范围
|
|
rangePorts, err := tp.parsePortRange(item)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("端口范围解析失败 %s: %v", item, err)
|
|
}
|
|
|
|
// 检查范围大小
|
|
if len(rangePorts) > tp.options.MaxPortRange {
|
|
return nil, fmt.Errorf("端口范围过大: %d, 最大允许: %d", len(rangePorts), tp.options.MaxPortRange)
|
|
}
|
|
|
|
ports = append(ports, rangePorts...)
|
|
} else {
|
|
// 单个端口
|
|
port, err := strconv.Atoi(item)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("无效端口号: %s", item)
|
|
}
|
|
|
|
if port < 1 || port > 65535 {
|
|
return nil, fmt.Errorf("端口号超出范围: %d", port)
|
|
}
|
|
|
|
ports = append(ports, port)
|
|
}
|
|
}
|
|
|
|
return ports, nil
|
|
}
|
|
|
|
// parseCIDR 解析CIDR网段
|
|
func (tp *TargetParser) parseCIDR(cidr string) ([]string, error) {
|
|
_, ipNet, err := net.ParseCIDR(cidr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var ips []string
|
|
ip := ipNet.IP.Mask(ipNet.Mask)
|
|
|
|
for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); tp.nextIP(ip) {
|
|
ips = append(ips, ip.String())
|
|
|
|
// 防止生成过多IP
|
|
if len(ips) > tp.options.MaxTargets {
|
|
break
|
|
}
|
|
}
|
|
|
|
return ips, nil
|
|
}
|
|
|
|
// parseIPRange 解析IP范围
|
|
func (tp *TargetParser) parseIPRange(rangeStr string) ([]string, error) {
|
|
parts := strings.Split(rangeStr, "-")
|
|
if len(parts) != 2 {
|
|
return nil, fmt.Errorf("无效的IP范围格式")
|
|
}
|
|
|
|
startIP := net.ParseIP(strings.TrimSpace(parts[0]))
|
|
endIP := net.ParseIP(strings.TrimSpace(parts[1]))
|
|
|
|
if startIP == nil || endIP == nil {
|
|
return nil, fmt.Errorf("无效的IP地址")
|
|
}
|
|
|
|
var ips []string
|
|
for ip := startIP; !ip.Equal(endIP); tp.nextIP(ip) {
|
|
ips = append(ips, ip.String())
|
|
|
|
// 防止生成过多IP
|
|
if len(ips) > tp.options.MaxTargets {
|
|
break
|
|
}
|
|
}
|
|
ips = append(ips, endIP.String()) // 添加结束IP
|
|
|
|
return ips, nil
|
|
}
|
|
|
|
// parsePortRange 解析端口范围
|
|
func (tp *TargetParser) parsePortRange(rangeStr string) ([]int, error) {
|
|
parts := strings.Split(rangeStr, "-")
|
|
if len(parts) != 2 {
|
|
return nil, fmt.Errorf("无效的端口范围格式")
|
|
}
|
|
|
|
startPort, err1 := strconv.Atoi(strings.TrimSpace(parts[0]))
|
|
endPort, err2 := strconv.Atoi(strings.TrimSpace(parts[1]))
|
|
|
|
if err1 != nil || err2 != nil {
|
|
return nil, fmt.Errorf("无效的端口号")
|
|
}
|
|
|
|
if startPort > endPort {
|
|
startPort, endPort = endPort, startPort
|
|
}
|
|
|
|
if startPort < 1 || endPort > 65535 {
|
|
return nil, fmt.Errorf("端口号超出范围")
|
|
}
|
|
|
|
var ports []int
|
|
for port := startPort; port <= endPort; port++ {
|
|
ports = append(ports, port)
|
|
}
|
|
|
|
return ports, nil
|
|
}
|
|
|
|
// nextIP 获取下一个IP地址
|
|
func (tp *TargetParser) nextIP(ip net.IP) {
|
|
for j := len(ip) - 1; j >= 0; j-- {
|
|
ip[j]++
|
|
if ip[j] > 0 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// validateHost 验证主机地址
|
|
func (tp *TargetParser) validateHost(host string) (bool, error) {
|
|
if host == "" {
|
|
return false, fmt.Errorf("主机地址为空")
|
|
}
|
|
|
|
// 检查是否为IP地址
|
|
if ip := net.ParseIP(host); ip != nil {
|
|
return tp.validateIP(ip)
|
|
}
|
|
|
|
// 检查是否为域名
|
|
if tp.isValidDomain(host) {
|
|
return true, nil
|
|
}
|
|
|
|
return false, fmt.Errorf("无效的主机地址格式")
|
|
}
|
|
|
|
// validateIP 验证IP地址
|
|
func (tp *TargetParser) validateIP(ip net.IP) (bool, error) {
|
|
if ip == nil {
|
|
return false, fmt.Errorf("IP地址为空")
|
|
}
|
|
|
|
// 检查是否为私有IP
|
|
if !tp.options.AllowPrivateIPs && tp.isPrivateIP(ip) {
|
|
return false, fmt.Errorf("不允许私有IP地址")
|
|
}
|
|
|
|
// 检查是否为回环地址
|
|
if !tp.options.AllowLoopback && ip.IsLoopback() {
|
|
return false, fmt.Errorf("不允许回环地址")
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// validateURL 验证URL
|
|
func (tp *TargetParser) validateURL(rawURL string) (bool, error) {
|
|
if rawURL == "" {
|
|
return false, fmt.Errorf("URL为空")
|
|
}
|
|
|
|
if !tp.options.ValidateURLs {
|
|
return true, nil
|
|
}
|
|
|
|
if !tp.urlRegex.MatchString(rawURL) {
|
|
return false, fmt.Errorf("URL格式无效")
|
|
}
|
|
|
|
// 进一步验证URL格式
|
|
_, err := url.Parse(rawURL)
|
|
if err != nil {
|
|
return false, fmt.Errorf("URL解析失败: %v", err)
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// validateHostPort 验证主机端口组合
|
|
func (tp *TargetParser) validateHostPort(hostPort string) (bool, error) {
|
|
parts := strings.Split(hostPort, ":")
|
|
if len(parts) != 2 {
|
|
return false, fmt.Errorf("主机端口格式无效,应为 host:port")
|
|
}
|
|
|
|
host := strings.TrimSpace(parts[0])
|
|
portStr := strings.TrimSpace(parts[1])
|
|
|
|
// 验证主机
|
|
if valid, err := tp.validateHost(host); !valid {
|
|
return false, fmt.Errorf("主机无效: %v", err)
|
|
}
|
|
|
|
// 验证端口
|
|
port, err := strconv.Atoi(portStr)
|
|
if err != nil {
|
|
return false, fmt.Errorf("端口号无效: %s", portStr)
|
|
}
|
|
|
|
if port < 1 || port > 65535 {
|
|
return false, fmt.Errorf("端口号超出范围: %d", port)
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// isPrivateIP 检查是否为私有IP
|
|
func (tp *TargetParser) isPrivateIP(ip net.IP) bool {
|
|
if ip4 := ip.To4(); ip4 != nil {
|
|
// 10.0.0.0/8
|
|
if ip4[0] == 10 {
|
|
return true
|
|
}
|
|
// 172.16.0.0/12
|
|
if ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31 {
|
|
return true
|
|
}
|
|
// 192.168.0.0/16
|
|
if ip4[0] == 192 && ip4[1] == 168 {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// isValidDomain 检查是否为有效域名
|
|
func (tp *TargetParser) isValidDomain(domain string) bool {
|
|
domainRegex := regexp.MustCompile(`^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$`)
|
|
return domainRegex.MatchString(domain) && len(domain) <= 253
|
|
}
|
|
|
|
// excludeHosts 排除指定主机
|
|
func (tp *TargetParser) excludeHosts(hosts, excludeList []string) []string {
|
|
excludeMap := make(map[string]struct{})
|
|
for _, exclude := range excludeList {
|
|
excludeMap[exclude] = struct{}{}
|
|
}
|
|
|
|
var result []string
|
|
for _, host := range hosts {
|
|
if _, excluded := excludeMap[host]; !excluded {
|
|
result = append(result, host)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// removeDuplicateStrings 去重字符串切片
|
|
func (tp *TargetParser) removeDuplicateStrings(slice []string) []string {
|
|
seen := make(map[string]struct{})
|
|
var result []string
|
|
|
|
for _, item := range slice {
|
|
if _, exists := seen[item]; !exists {
|
|
seen[item] = struct{}{}
|
|
result = append(result, item)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// removeDuplicatePorts 去重端口切片
|
|
func (tp *TargetParser) removeDuplicatePorts(slice []int) []int {
|
|
seen := make(map[int]struct{})
|
|
var result []int
|
|
|
|
for _, item := range slice {
|
|
if _, exists := seen[item]; !exists {
|
|
seen[item] = struct{}{}
|
|
result = append(result, item)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// generateStatistics 生成统计信息
|
|
func (tp *TargetParser) generateStatistics(hosts, urls []string, ports, excludePorts []int) *TargetStatistics {
|
|
return &TargetStatistics{
|
|
TotalHosts: len(hosts),
|
|
TotalURLs: len(urls),
|
|
TotalPorts: len(ports),
|
|
ExcludedPorts: len(excludePorts),
|
|
}
|
|
}
|
|
|
|
// Validate 验证解析结果
|
|
func (tp *TargetParser) Validate() error {
|
|
return nil
|
|
}
|
|
|
|
// GetStatistics 获取解析统计
|
|
func (tp *TargetParser) GetStatistics() interface{} {
|
|
tp.mu.RLock()
|
|
defer tp.mu.RUnlock()
|
|
|
|
return map[string]interface{}{
|
|
"parser_type": "target",
|
|
"options": tp.options,
|
|
}
|
|
} |