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: "21,22,23,80,81,110,135,139,143,389,443,445,502,873,993,995,1433,1521,3306,5432,5672,6379,7001,7687,8000,8005,8009,8080,8089,8443,9000,9042,9092,9200,10051,11211,15672,27017,61616", } } // 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格式 switch { case item == "192": // 常用内网段简写 cidrHosts, err := tp.parseCIDR("192.168.0.0/16") if err != nil { return nil, fmt.Errorf("192网段解析失败: %v", err) } hosts = append(hosts, cidrHosts...) case item == "172": // 常用内网段简写 cidrHosts, err := tp.parseCIDR("172.16.0.0/12") if err != nil { return nil, fmt.Errorf("172网段解析失败: %v", err) } hosts = append(hosts, cidrHosts...) case item == "10": // 常用内网段简写 cidrHosts, err := tp.parseCIDR("10.0.0.0/8") if err != nil { return nil, fmt.Errorf("10网段解析失败: %v", err) } hosts = append(hosts, cidrHosts...) case strings.HasSuffix(item, "/8"): // 处理/8网段(使用采样方式) sampledHosts := tp.parseSubnet8(item) hosts = append(hosts, sampledHosts...) case 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...) case 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...) default: // 单个IP或域名 hosts = append(hosts, item) } } return hosts, nil } // parsePortList 解析端口列表,支持预定义端口组 func (tp *TargetParser) parsePortList(portStr string) ([]int, error) { if portStr == "" { return nil, nil } // 检查是否为预定义端口组 portStr = tp.expandPortGroups(portStr) 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 } // expandPortGroups 展开预定义端口组 func (tp *TargetParser) expandPortGroups(portStr string) string { portGroups := map[string]string{ "service": "21,22,23,25,110,135,139,143,162,389,445,465,502,587,636,873,993,995,1433,1521,2222,3306,3389,5020,5432,5672,5671,6379,8161,8443,9000,9092,9093,9200,10051,11211,15672,15671,27017,61616,61613", "db": "1433,1521,3306,5432,5672,6379,7687,9042,9093,9200,11211,27017,61616", "web": "80,81,82,83,84,85,86,87,88,89,90,91,92,98,99,443,800,801,808,880,888,889,1000,1010,1080,1081,1082,1099,1118,1888,2008,2020,2100,2375,2379,3000,3008,3128,3505,5555,6080,6648,6868,7000,7001,7002,7003,7004,7005,7007,7008,7070,7071,7074,7078,7080,7088,7200,7680,7687,7688,7777,7890,8000,8001,8002,8003,8004,8005,8006,8008,8009,8010,8011,8012,8016,8018,8020,8028,8030,8038,8042,8044,8046,8048,8053,8060,8069,8070,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096,8097,8098,8099,8100,8101,8108,8118,8161,8172,8180,8181,8200,8222,8244,8258,8280,8288,8300,8360,8443,8448,8484,8800,8834,8838,8848,8858,8868,8879,8880,8881,8888,8899,8983,8989,9000,9001,9002,9008,9010,9043,9060,9080,9081,9082,9083,9084,9085,9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9200,9443,9448,9800,9981,9986,9988,9998,9999,10000,10001,10002,10004,10008,10010,10051,10250,12018,12443,14000,15672,15671,16080,18000,18001,18002,18004,18008,18080,18082,18088,18090,18098,19001,20000,20720,20880,21000,21501,21502,28018", "all": "1-65535", "main": "21,22,23,80,81,110,135,139,143,389,443,445,502,873,993,995,1433,1521,3306,5432,5672,6379,7001,7687,8000,8005,8009,8080,8089,8443,9000,9042,9092,9200,10051,11211,15672,27017,61616", } if expandedPorts, exists := portGroups[portStr]; exists { return expandedPorts } return portStr } // 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 := make(net.IP, len(ipNet.IP)) copy(ip, ipNet.IP) count := 0 for ipNet.Contains(ip) { ips = append(ips, ip.String()) count++ // 防止生成过多IP if count >= tp.options.MaxTargets { break } tp.nextIP(ip) } 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范围格式") } startIPStr := strings.TrimSpace(parts[0]) endIPStr := strings.TrimSpace(parts[1]) // 验证起始IP startIP := net.ParseIP(startIPStr) if startIP == nil { return nil, fmt.Errorf("无效的起始IP地址: %s", startIPStr) } // 处理简写格式 (如: 192.168.1.1-100) if len(endIPStr) < 4 || !strings.Contains(endIPStr, ".") { return tp.parseShortIPRange(startIPStr, endIPStr) } // 处理完整格式 (如: 192.168.1.1-192.168.1.100) endIP := net.ParseIP(endIPStr) if endIP == nil { return nil, fmt.Errorf("无效的结束IP地址: %s", endIPStr) } return tp.parseFullIPRange(startIP, endIP) } // parseShortIPRange 解析简写格式的IP范围 func (tp *TargetParser) parseShortIPRange(startIPStr, endSuffix string) ([]string, error) { // 将结束段转换为数字 endNum, err := strconv.Atoi(endSuffix) if err != nil || endNum > 255 { return nil, fmt.Errorf("无效的IP范围结束值: %s", endSuffix) } // 分解起始IP ipParts := strings.Split(startIPStr, ".") if len(ipParts) != 4 { return nil, fmt.Errorf("无效的IP地址格式: %s", startIPStr) } // 获取前缀和起始IP的最后一部分 prefixIP := strings.Join(ipParts[0:3], ".") startNum, err := strconv.Atoi(ipParts[3]) if err != nil || startNum > endNum { return nil, fmt.Errorf("无效的IP范围: %s-%s", startIPStr, endSuffix) } // 生成IP范围 var allIP []string for i := startNum; i <= endNum; i++ { allIP = append(allIP, fmt.Sprintf("%s.%d", prefixIP, i)) } return allIP, nil } // parseFullIPRange 解析完整格式的IP范围 func (tp *TargetParser) parseFullIPRange(startIP, endIP net.IP) ([]string, error) { // 转换为IPv4 start4 := startIP.To4() end4 := endIP.To4() if start4 == nil || end4 == nil { return nil, fmt.Errorf("仅支持IPv4地址范围") } // 计算IP地址的整数表示 startInt := (int(start4[0]) << 24) | (int(start4[1]) << 16) | (int(start4[2]) << 8) | int(start4[3]) endInt := (int(end4[0]) << 24) | (int(end4[1]) << 16) | (int(end4[2]) << 8) | int(end4[3]) // 检查范围的有效性 if startInt > endInt { return nil, fmt.Errorf("起始IP大于结束IP") } // 限制IP范围的大小,防止生成过多IP导致内存问题 if endInt-startInt > tp.options.MaxTargets { return nil, fmt.Errorf("IP范围过大,超过最大限制: %d", tp.options.MaxTargets) } // 生成IP范围 var allIP []string for ipInt := startInt; ipInt <= endInt; ipInt++ { ip := fmt.Sprintf("%d.%d.%d.%d", (ipInt>>24)&0xFF, (ipInt>>16)&0xFF, (ipInt>>8)&0xFF, ipInt&0xFF) allIP = append(allIP, ip) } return allIP, nil } // parseSubnet8 解析/8网段的IP地址,生成采样IP列表 func (tp *TargetParser) parseSubnet8(subnet string) []string { // 去除CIDR后缀获取基础IP baseIP := subnet[:len(subnet)-2] if net.ParseIP(baseIP) == nil { return nil } // 获取/8网段的第一段 firstOctet := strings.Split(baseIP, ".")[0] var sampleIPs []string // 对常用网段进行更全面的扫描 commonSecondOctets := []int{0, 1, 2, 10, 100, 200, 254} // 对于每个选定的第二段,采样部分第三段 for _, secondOctet := range commonSecondOctets { for thirdOctet := 0; thirdOctet < 256; thirdOctet += 10 { // 添加常见的网关和服务器IP sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.1", firstOctet, secondOctet, thirdOctet)) // 默认网关 sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.254", firstOctet, secondOctet, thirdOctet)) // 通常用于路由器/交换机 // 随机采样不同范围的主机IP fourthOctet := tp.randomInt(2, 253) sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.%d", firstOctet, secondOctet, thirdOctet, fourthOctet)) } } // 对其他二级网段进行稀疏采样 samplingStep := 32 // 每32个二级网段采样1个 for secondOctet := 0; secondOctet < 256; secondOctet += samplingStep { for thirdOctet := 0; thirdOctet < 256; thirdOctet += samplingStep { // 对于采样的网段,取几个代表性IP sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.1", firstOctet, secondOctet, thirdOctet)) sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.%d", firstOctet, secondOctet, thirdOctet, tp.randomInt(2, 253))) } } // 限制采样数量 if len(sampleIPs) > tp.options.MaxTargets { sampleIPs = sampleIPs[:tp.options.MaxTargets] } return sampleIPs } // randomInt 生成指定范围内的随机整数 func (tp *TargetParser) randomInt(min, max int) int { if min >= max || min < 0 || max <= 0 { return max } return min + (max-min)/2 // 简化版本,避免依赖rand } // 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, } }