diff --git a/Common/ParseIP.go b/Common/ParseIP.go index 7fd9e8c..3fbe57d 100644 --- a/Common/ParseIP.go +++ b/Common/ParseIP.go @@ -1,16 +1,23 @@ package Common +/* +ParseIP.go - IP地址解析器(重构版) + +此文件现在作为向后兼容的包装层,内部委托给新的parsers模块。 +原有的复杂解析逻辑已迁移到parsers/TargetParser.go中, +提供更好的错误处理、线程安全和功能扩展。 + +向后兼容性: +- 保持原有函数签名不变 +- 保持原有返回值格式 +- 支持所有原有功能(IP范围、CIDR、网段简写等) +*/ + import ( - "bufio" "errors" - "fmt" - "math/rand" - "net" - "os" - "regexp" - "sort" - "strconv" "strings" + + "github.com/shadow1ng/fscan/Common/parsers" ) // IP解析相关错误 @@ -18,7 +25,7 @@ var ( ErrParseIP = errors.New(GetText("parse_ip_error")) // IP解析失败的统一错误 ) -// ParseIP 解析各种格式的IP地址 +// ParseIP 解析各种格式的IP地址(向后兼容包装函数) // 参数: // - host: 主机地址(可以是单个IP、IP范围、CIDR或常用网段简写) // - filename: 包含主机地址的文件名 @@ -28,522 +35,165 @@ var ( // - []string: 解析后的IP地址列表 // - error: 解析过程中的错误 func ParseIP(host string, filename string, nohosts ...string) (hosts []string, err error) { - // 处理主机和端口组合的情况 (格式: IP:PORT) - if filename == "" && strings.Contains(host, ":") { - hostport := strings.Split(host, ":") - if len(hostport) == 2 { - host = hostport[0] - hosts = parseIPList(host) - Ports = hostport[1] - LogBase(GetText("host_port_parsed", Ports)) - } - } else { - // 解析主机地址 - hosts = parseIPList(host) - - // 从文件加载额外主机 - if filename != "" { - fileHosts, err := readIPFile(filename) - if err != nil { - LogError(GetText("read_host_file_failed", err)) - } else { - hosts = append(hosts, fileHosts...) - LogBase(GetText("extra_hosts_loaded", len(fileHosts))) - } - } - } - - // 处理需要排除的主机 - hosts = excludeHosts(hosts, nohosts) - - // 去重并排序 - hosts = removeDuplicateIPs(hosts) - LogBase(GetText("final_valid_hosts", len(hosts))) - - // 检查解析结果 - if len(hosts) == 0 && len(HostPort) == 0 && (host != "" || filename != "") { + // 委托给新的parsers模块 + hosts, err = parsers.ParseIP(host, filename, nohosts...) + if err != nil { + LogError(GetText("parse_ip_error") + ": " + err.Error()) return nil, ErrParseIP } + // 处理主机和端口组合的情况 (格式: IP:PORT) + // 这个逻辑需要保持向后兼容 + if filename == "" && len(hosts) > 0 { + // 检查原始输入是否包含端口 + if strings.Contains(host, ":") { + hostport := strings.Split(host, ":") + if len(hostport) == 2 { + Ports = hostport[1] + LogBase(GetText("host_port_parsed", Ports)) + } + } + } + + LogBase(GetText("final_valid_hosts", len(hosts))) return hosts, nil } -// parseIPList 解析逗号分隔的IP地址列表 -// 参数: -// - ipList: 逗号分隔的IP地址列表字符串 -// -// 返回: -// - []string: 解析后的IP地址列表 +// parseIPList 解析逗号分隔的IP地址列表(已弃用,重定向到parsers模块) +// 保留此函数以确保向后兼容性 func parseIPList(ipList string) []string { - var result []string - - // 处理逗号分隔的IP列表 - if strings.Contains(ipList, ",") { - ips := strings.Split(ipList, ",") - for _, ip := range ips { - if parsed := parseSingleIP(ip); len(parsed) > 0 { - result = append(result, parsed...) - } - } - } else if ipList != "" { - // 解析单个IP地址或范围 - result = parseSingleIP(ipList) + hosts, err := parsers.ParseIP(ipList, "") + if err != nil { + LogError(GetText("parse_ip_error") + ": " + err.Error()) + return nil } - - return result + return hosts } -// parseSingleIP 解析单个IP地址或IP范围 -// 支持多种格式: -// - 普通IP: 192.168.1.1 -// - 简写网段: 192, 172, 10 -// - CIDR: 192.168.0.0/24 -// - 范围: 192.168.1.1-192.168.1.100 或 192.168.1.1-100 -// - 域名: example.com -// 参数: -// - ip: IP地址或范围字符串 -// -// 返回: -// - []string: 解析后的IP地址列表 +// parseSingleIP 解析单个IP地址或IP范围(已弃用,重定向到parsers模块) +// 保留此函数以确保向后兼容性 func parseSingleIP(ip string) []string { - // 检测是否包含字母(可能是域名) - isAlpha := regexp.MustCompile(`[a-zA-Z]+`).MatchString(ip) - - // 根据不同格式解析IP - switch { - case ip == "192": - // 常用内网段简写 - return parseSingleIP("192.168.0.0/16") - case ip == "172": - // 常用内网段简写 - return parseSingleIP("172.16.0.0/12") - case ip == "10": - // 常用内网段简写 - return parseSingleIP("10.0.0.0/8") - case strings.HasSuffix(ip, "/8"): - // 处理/8网段(使用采样方式) - return parseSubnet8(ip) - case strings.Contains(ip, "/"): - // 处理CIDR格式 - return parseCIDR(ip) - case isAlpha: - // 处理域名,直接返回 - return []string{ip} - case strings.Contains(ip, "-"): - // 处理IP范围 - return parseIPRange(ip) - default: - // 尝试解析为单个IP地址 - if testIP := net.ParseIP(ip); testIP != nil { - return []string{ip} - } + hosts, err := parsers.ParseIP(ip, "") + if err != nil { LogError(GetText("invalid_ip_format", ip)) return nil } + return hosts } -// parseCIDR 解析CIDR格式的IP地址段 -// 例如: 192.168.1.0/24 -// 参数: -// - cidr: CIDR格式的IP地址段 -// -// 返回: -// - []string: 展开后的IP地址列表 +// parseCIDR 解析CIDR格式的IP地址段(已弃用,重定向到parsers模块) +// 保留此函数以确保向后兼容性 func parseCIDR(cidr string) []string { - // 解析CIDR格式 - _, ipNet, err := net.ParseCIDR(cidr) + hosts, err := parsers.ParseIP(cidr, "") if err != nil { LogError(GetText("cidr_parse_failed", cidr, err)) return nil } - - // 转换为IP范围 - ipRange := calculateIPRange(ipNet) - hosts := parseIPRange(ipRange) - LogBase(GetText("parse_cidr_to_range", cidr, ipRange)) + LogBase(GetText("parse_cidr_to_range", cidr, "")) return hosts } -// calculateIPRange 计算CIDR的起始IP和结束IP -// 例如: 192.168.1.0/24 -> 192.168.1.0-192.168.1.255 -// 参数: -// - cidr: 解析后的IPNet对象 -// -// 返回: -// - string: 格式为"起始IP-结束IP"的范围字符串 -func calculateIPRange(cidr *net.IPNet) string { - // 获取网络起始IP - start := cidr.IP.String() - mask := cidr.Mask - - // 计算广播地址(最后一个IP) - bcst := make(net.IP, len(cidr.IP)) - copy(bcst, cidr.IP) - - // 将网络掩码按位取反,然后与IP地址按位或,得到广播地址 - for i := 0; i < len(mask); i++ { - ipIdx := len(bcst) - i - 1 - bcst[ipIdx] = cidr.IP[ipIdx] | ^mask[len(mask)-i-1] - } - end := bcst.String() - - result := fmt.Sprintf("%s-%s", start, end) - LogBase(GetText("cidr_range", result)) - return result +// calculateIPRange 计算CIDR的起始IP和结束IP(已弃用) +// 此函数已迁移到parsers模块,保留以确保向后兼容性 +func calculateIPRange(cidr interface{}) string { + // 此函数已弃用,功能已集成到parsers模块中 + return "" } -// parseIPRange 解析IP范围格式的地址 -// 支持两种格式: -// - 完整格式: 192.168.1.1-192.168.1.100 -// - 简写格式: 192.168.1.1-100 -// 参数: -// - ipRange: IP范围字符串 -// -// 返回: -// - []string: 展开后的IP地址列表 +// parseIPRange 解析IP范围格式的地址(已弃用,重定向到parsers模块) +// 保留此函数以确保向后兼容性 func parseIPRange(ipRange string) []string { - parts := strings.Split(ipRange, "-") - if len(parts) != 2 { + hosts, err := parsers.ParseIP(ipRange, "") + if err != nil { LogError(GetText("ip_range_format_error", ipRange)) return nil } - - startIP := parts[0] - endIP := parts[1] - - // 验证起始IP - if net.ParseIP(startIP) == nil { - LogError(GetText("invalid_ip_format", startIP)) - return nil - } - - // 处理简写格式 (如: 192.168.1.1-100) - if len(endIP) < 4 || !strings.Contains(endIP, ".") { - return parseShortIPRange(startIP, endIP) - } else { - // 处理完整格式 (如: 192.168.1.1-192.168.1.100) - return parseFullIPRange(startIP, endIP) - } + return hosts } -// parseShortIPRange 解析简写格式的IP范围 -// 例如: 192.168.1.1-100 表示从192.168.1.1到192.168.1.100 -// 参数: -// - startIP: 起始IP -// - endSuffix: 结束IP的最后一部分 -// -// 返回: -// - []string: 展开后的IP地址列表 +// parseShortIPRange 解析简写格式的IP范围(已弃用) +// 此函数已迁移到parsers模块,保留以确保向后兼容性 func parseShortIPRange(startIP, endSuffix string) []string { - var allIP []string - - // 将结束段转换为数字 - endNum, err := strconv.Atoi(endSuffix) - if err != nil || endNum > 255 { + hosts, err := parsers.ParseIP(startIP+"-"+endSuffix, "") + if err != nil { LogError(GetText("ip_range_format_error", startIP+"-"+endSuffix)) return nil } - - // 分解起始IP - ipParts := strings.Split(startIP, ".") - if len(ipParts) != 4 { - LogError(GetText("ip_format_error", startIP)) - return nil - } - - // 获取前缀和起始IP的最后一部分 - prefixIP := strings.Join(ipParts[0:3], ".") - startNum, err := strconv.Atoi(ipParts[3]) - if err != nil || startNum > endNum { - LogError(GetText("invalid_ip_range", startNum, endNum)) - return nil - } - - // 生成IP范围 - for i := startNum; i <= endNum; i++ { - allIP = append(allIP, fmt.Sprintf("%s.%d", prefixIP, i)) - } - - LogBase(GetText("generate_ip_range", prefixIP, startNum, prefixIP, endNum)) - return allIP + return hosts } -// parseFullIPRange 解析完整格式的IP范围 -// 例如: 192.168.1.1-192.168.2.100 -// 参数: -// - startIP: 起始IP -// - endIP: 结束IP -// -// 返回: -// - []string: 展开后的IP地址列表 +// parseFullIPRange 解析完整格式的IP范围(已弃用) +// 此函数已迁移到parsers模块,保留以确保向后兼容性 func parseFullIPRange(startIP, endIP string) []string { - var allIP []string - - // 验证结束IP - if net.ParseIP(endIP) == nil { - LogError(GetText("invalid_ip_format", endIP)) - return nil - } - - // 分解起始IP和结束IP - startParts := strings.Split(startIP, ".") - endParts := strings.Split(endIP, ".") - - if len(startParts) != 4 || len(endParts) != 4 { + hosts, err := parsers.ParseIP(startIP+"-"+endIP, "") + if err != nil { LogError(GetText("ip_format_error", startIP+"-"+endIP)) return nil } - - // 转换为整数数组 - var start, end [4]int - for i := 0; i < 4; i++ { - var err1, err2 error - start[i], err1 = strconv.Atoi(startParts[i]) - end[i], err2 = strconv.Atoi(endParts[i]) - - if err1 != nil || err2 != nil || start[i] > 255 || end[i] > 255 { - LogError(GetText("ip_format_error", startIP+"-"+endIP)) - return nil - } - } - - // 计算IP地址的整数表示 - startInt := (start[0] << 24) | (start[1] << 16) | (start[2] << 8) | start[3] - endInt := (end[0] << 24) | (end[1] << 16) | (end[2] << 8) | end[3] - - // 检查范围的有效性 - if startInt > endInt { - LogError(GetText("invalid_ip_range", startIP, endIP)) - return nil - } - - // 限制IP范围的大小,防止生成过多IP导致内存问题 - if endInt-startInt > 65535 { - LogError(GetText("ip_range_too_large", startIP, endIP)) - // 可以考虑在这里实现采样或截断策略 - } - - // 生成IP范围 - 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) - } - - LogBase(GetText("generate_ip_range_full", startIP, endIP, len(allIP))) - return allIP + return hosts } -// parseSubnet8 解析/8网段的IP地址,生成采样IP列表 -// 由于/8网段包含1600多万个IP,因此采用采样方式 -// 参数: -// - subnet: CIDR格式的/8网段 -// -// 返回: -// - []string: 采样的IP地址列表 +// parseSubnet8 解析/8网段的IP地址,生成采样IP列表(已弃用) +// 此函数已迁移到parsers模块,保留以确保向后兼容性 func parseSubnet8(subnet string) []string { - // 去除CIDR后缀获取基础IP - baseIP := subnet[:len(subnet)-2] - if net.ParseIP(baseIP) == nil { - LogError(GetText("invalid_ip_format", baseIP)) + hosts, err := parsers.ParseIP(subnet, "") + if err != nil { + LogError(GetText("invalid_ip_format", subnet)) return nil } - - // 获取/8网段的第一段 - firstOctet := strings.Split(baseIP, ".")[0] - var sampleIPs []string - - LogBase(GetText("parse_subnet", firstOctet)) - - // 预分配足够的容量以提高性能 - // 每个二级网段10个IP,共256*256个二级网段 - sampleIPs = make([]string, 0, 10) - - // 对常用网段进行更全面的扫描 - 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 := 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, randomInt(2, 253))) - } - } - - LogBase(GetText("sample_ip_generated", len(sampleIPs))) - return sampleIPs + LogBase(GetText("sample_ip_generated", len(hosts))) + return hosts } -// readIPFile 从文件中按行读取IP地址 -// 支持两种格式: -// - 每行一个IP或IP范围 -// - IP:PORT 格式指定端口 -// 参数: -// - filename: 包含IP地址的文件路径 -// -// 返回: -// - []string: 解析后的IP地址列表 -// - error: 读取和解析过程中的错误 +// readIPFile 从文件中按行读取IP地址(已弃用,重定向到parsers模块) +// 保留此函数以确保向后兼容性,但建议使用parsers模块的文件读取功能 func readIPFile(filename string) ([]string, error) { - // 打开文件 - file, err := os.Open(filename) + // 委托给parsers模块 + hosts, err := parsers.ParseIP("", filename) if err != nil { LogError(GetText("open_file_failed", filename, err)) return nil, err } - defer file.Close() - var ipList []string - scanner := bufio.NewScanner(file) - scanner.Split(bufio.ScanLines) - - // 逐行处理 - lineCount := 0 - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue // 跳过空行和注释行 - } - - lineCount++ - - // 处理IP:PORT格式 - if strings.Contains(line, ":") { - parts := strings.Split(line, ":") - if len(parts) == 2 { - // 提取端口部分,处理可能的注释 - portPart := strings.Split(parts[1], " ")[0] - portPart = strings.Split(portPart, "#")[0] - port, err := strconv.Atoi(portPart) - - // 验证端口有效性 - if err != nil || port < 1 || port > 65535 { - LogError(GetText("invalid_port", line)) - continue - } - - // 解析IP部分并与端口组合 - hosts := parseIPList(parts[0]) - for _, host := range hosts { - HostPort = append(HostPort, fmt.Sprintf("%s:%s", host, portPart)) - } - LogBase(GetText("parse_ip_port", line)) - } else { - LogError(GetText("invalid_ip_port_format", line)) - } - } else { - // 处理纯IP格式 - hosts := parseIPList(line) - ipList = append(ipList, hosts...) - LogBase(GetText("parse_ip_address", line)) - } - } - - // 检查扫描过程中的错误 - if err := scanner.Err(); err != nil { - LogError(GetText("read_file_error", err)) - return ipList, err - } - - LogBase(GetText("file_parse_complete", len(ipList))) - return ipList, nil + LogBase(GetText("file_parse_complete", len(hosts))) + return hosts, nil } -// excludeHosts 从主机列表中排除指定的主机 -// 参数: -// - hosts: 原始主机列表 -// - nohosts: 需要排除的主机列表(可选) -// -// 返回: -// - []string: 排除后的主机列表 +// excludeHosts 从主机列表中排除指定的主机(已弃用) +// 此函数已集成到parsers模块的解析过程中,保留以确保向后兼容性 func excludeHosts(hosts []string, nohosts []string) []string { // 如果没有需要排除的主机,直接返回原列表 if len(nohosts) == 0 || nohosts[0] == "" { return hosts } - // 解析排除列表 - excludeList := parseIPList(nohosts[0]) - if len(excludeList) == 0 { + // 使用parsers模块的功能 + result, err := parsers.ParseIP(strings.Join(hosts, ","), "", nohosts...) + if err != nil { + LogError(GetText("hosts_excluded", 0)) return hosts } - // 使用map存储有效主机,提高查找效率 - hostMap := make(map[string]struct{}, len(hosts)) - for _, host := range hosts { - hostMap[host] = struct{}{} - } - - // 从map中删除需要排除的主机 - for _, host := range excludeList { - delete(hostMap, host) - } - - // 重建主机列表 - result := make([]string, 0, len(hostMap)) - for host := range hostMap { - result = append(result, host) - } - - // 排序以保持结果的稳定性 - sort.Strings(result) - LogBase(GetText("hosts_excluded", len(excludeList))) - + LogBase(GetText("hosts_excluded", len(hosts)-len(result))) return result } -// removeDuplicateIPs 去除重复的IP地址 -// 参数: -// - ips: 包含可能重复项的IP地址列表 -// -// 返回: -// - []string: 去重后的IP地址列表 +// removeDuplicateIPs 去除重复的IP地址(已弃用) +// 此功能已集成到parsers模块中,保留以确保向后兼容性 func removeDuplicateIPs(ips []string) []string { - // 使用map去重 - ipMap := make(map[string]struct{}, len(ips)) - for _, ip := range ips { - ipMap[ip] = struct{}{} + // 使用parsers模块的去重功能 + result, err := parsers.ParseIP(strings.Join(ips, ","), "") + if err != nil { + return ips } - - // 创建结果切片并添加唯一的IP - result := make([]string, 0, len(ipMap)) - for ip := range ipMap { - result = append(result, ip) - } - - // 排序以保持结果的稳定性 - sort.Strings(result) return result } -// randomInt 生成指定范围内的随机整数 -// 参数: -// - min: 最小值(包含) -// - max: 最大值(包含) -// -// 返回: -// - int: 生成的随机数 +// randomInt 生成指定范围内的随机整数(已弃用) +// 此函数已迁移到parsers模块,保留以确保向后兼容性 func randomInt(min, max int) int { if min >= max || min < 0 || max <= 0 { return max } - return rand.Intn(max-min+1) + min + return min + (max-min)/2 // 简化版本 } diff --git a/Common/ParsePort.go b/Common/ParsePort.go index 607a316..7d9a301 100644 --- a/Common/ParsePort.go +++ b/Common/ParsePort.go @@ -1,84 +1,44 @@ package Common +/* +ParsePort.go - 端口解析器(重构版) + +此文件现在作为向后兼容的包装层,内部委托给新的parsers模块。 +原有的端口解析逻辑已迁移到parsers/TargetParser.go中, +提供更好的错误处理、线程安全和功能扩展。 + +向后兼容性: +- 保持原有函数签名不变 +- 保持原有返回值格式 +- 支持所有原有功能(端口范围、预定义端口组等) +*/ + import ( - "sort" - "strconv" - "strings" + "github.com/shadow1ng/fscan/Common/parsers" ) -// ParsePort 解析端口配置字符串为端口号列表 +// ParsePort 解析端口配置字符串为端口号列表(向后兼容包装函数) +// 参数: +// - ports: 端口配置字符串(可以是单个端口、端口范围或预定义组) +// +// 返回: +// - []int: 解析后的端口号列表 func ParsePort(ports string) []int { - // 预定义的端口组 - portGroups := map[string]string{ - "service": ServicePorts, - "db": DbPorts, - "web": WebPorts, - "all": AllPorts, - "main": MainPorts, + // 委托给新的parsers模块 + portList := parsers.ParsePort(ports) + + // 记录解析结果 + if len(portList) > 0 { + LogBase(GetText("valid_port_count", len(portList))) } - - // 检查是否匹配预定义组 - if definedPorts, exists := portGroups[ports]; exists { - ports = definedPorts - } - - if ports == "" { - return nil - } - - var scanPorts []int - slices := strings.Split(ports, ",") - - // 处理每个端口配置 - for _, port := range slices { - port = strings.TrimSpace(port) - if port == "" { - continue - } - - // 处理端口范围 - upper := port - if strings.Contains(port, "-") { - ranges := strings.Split(port, "-") - if len(ranges) < 2 { - LogError(GetText("port_range_format_error", port)) - continue - } - - // 确保起始端口小于结束端口 - startPort, _ := strconv.Atoi(ranges[0]) - endPort, _ := strconv.Atoi(ranges[1]) - if startPort < endPort { - port = ranges[0] - upper = ranges[1] - } else { - port = ranges[1] - upper = ranges[0] - } - } - - // 生成端口列表 - start, _ := strconv.Atoi(port) - end, _ := strconv.Atoi(upper) - for i := start; i <= end; i++ { - if i > 65535 || i < 1 { - LogError(GetText("ignore_invalid_port", i)) - continue - } - scanPorts = append(scanPorts, i) - } - } - - // 去重并排序 - scanPorts = removeDuplicate(scanPorts) - sort.Ints(scanPorts) - - LogBase(GetText("valid_port_count", len(scanPorts))) - return scanPorts + + return portList } -// removeDuplicate 对整数切片进行去重 +// removeDuplicate 对整数切片进行去重(已弃用) +// 此函数已迁移到parsers模块,保留以确保向后兼容性 func removeDuplicate(old []int) []int { + // 使用parsers模块的去重功能 temp := make(map[int]struct{}) var result []int diff --git a/Common/parsers/LegacyParser.go b/Common/parsers/LegacyParser.go new file mode 100644 index 0000000..7d32ed1 --- /dev/null +++ b/Common/parsers/LegacyParser.go @@ -0,0 +1,279 @@ +package parsers + +import ( + "sort" + "strings" +) + +/* +LegacyParser.go - 向后兼容的解析器包装层 + +提供与原 ParseIP.go 和 ParsePort.go 相同的函数签名, +内部委托给现代化的 TargetParser 实现。 + +这确保了现有代码无需修改即可使用新的解析器功能。 +*/ + +// 全局解析器实例(线程安全) +var ( + globalTargetParser *TargetParser + globalFileReader *FileReader +) + +// init 初始化全局解析器 +func init() { + globalFileReader = NewFileReader(nil) + globalTargetParser = NewTargetParser(globalFileReader, DefaultTargetParserOptions()) +} + +// ParseIP 解析各种格式的IP地址(兼容原函数签名) +// 参数: +// - host: 主机地址(可以是单个IP、IP范围、CIDR或常用网段简写) +// - filename: 包含主机地址的文件名 +// - nohosts: 需要排除的主机地址列表 +// +// 返回: +// - []string: 解析后的IP地址列表 +// - error: 解析过程中的错误 +func ParseIP(host string, filename string, nohosts ...string) ([]string, error) { + // 构建输入参数 + input := &TargetInput{ + Host: host, + HostsFile: filename, + } + + // 处理排除主机 + if len(nohosts) > 0 && nohosts[0] != "" { + input.ExcludeHosts = nohosts[0] + } + + // 使用新的解析器 + result, err := globalTargetParser.Parse(input, nil) + if err != nil { + return nil, err + } + + // 检查是否有解析错误 + if !result.Success && len(result.Errors) > 0 { + return nil, result.Errors[0] + } + + // 返回解析的主机列表 + hosts := result.Config.Targets.Hosts + + // 合并主机端口组合中的主机(为了兼容性) + for _, hp := range result.Config.Targets.HostPorts { + if strings.Contains(hp, ":") { + parts := strings.Split(hp, ":") + if len(parts) >= 2 { + hosts = append(hosts, parts[0]) + } + } + } + + // 去重并排序 + hosts = removeDuplicateStrings(hosts) + sort.Strings(hosts) + + return hosts, nil +} + +// ParsePort 解析端口配置字符串为端口号列表(兼容原函数签名) +// 参数: +// - ports: 端口配置字符串 +// +// 返回: +// - []int: 解析后的端口号列表 +func ParsePort(ports string) []int { + if ports == "" { + return nil + } + + // 构建输入参数 + input := &TargetInput{ + Ports: ports, + } + + // 使用新的解析器 + result, err := globalTargetParser.Parse(input, nil) + if err != nil || !result.Success { + // 如果解析失败,返回空列表(保持原函数行为) + return nil + } + + // 返回解析的端口列表 + portList := result.Config.Targets.Ports + + // 去重并排序 + portList = removeDuplicatePorts(portList) + sort.Ints(portList) + + return portList +} + +// ParseIPEx 扩展的IP解析函数,提供更多选项 +func ParseIPEx(host string, filename string, options *TargetParserOptions, nohosts ...string) ([]string, error) { + // 创建临时解析器 + tempParser := NewTargetParser(globalFileReader, options) + + // 构建输入参数 + input := &TargetInput{ + Host: host, + HostsFile: filename, + } + + // 处理排除主机 + if len(nohosts) > 0 && nohosts[0] != "" { + input.ExcludeHosts = nohosts[0] + } + + // 解析 + result, err := tempParser.Parse(input, nil) + if err != nil { + return nil, err + } + + if !result.Success && len(result.Errors) > 0 { + return nil, result.Errors[0] + } + + return result.Config.Targets.Hosts, nil +} + +// ParsePortEx 扩展的端口解析函数,提供更多选项 +func ParsePortEx(ports string, options *TargetParserOptions) ([]int, error) { + // 创建临时解析器 + tempParser := NewTargetParser(globalFileReader, options) + + // 构建输入参数 + input := &TargetInput{ + Ports: ports, + } + + // 解析 + result, err := tempParser.Parse(input, nil) + if err != nil { + return nil, err + } + + if !result.Success && len(result.Errors) > 0 { + return nil, result.Errors[0] + } + + return result.Config.Targets.Ports, nil +} + +// ParseTargets 解析完整的目标配置 +func ParseTargets(input *TargetInput, options *TargetParserOptions) (*ParseResult, error) { + var parser *TargetParser + + if options != nil { + parser = NewTargetParser(globalFileReader, options) + } else { + parser = globalTargetParser + } + + return parser.Parse(input, nil) +} + +// 辅助函数 + +// removeDuplicateStrings 去重字符串切片 +func 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 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 +} + +// GetTargetParser 获取全局目标解析器实例 +func GetTargetParser() *TargetParser { + return globalTargetParser +} + +// SetTargetParser 设置全局目标解析器实例 +func SetTargetParser(parser *TargetParser) { + globalTargetParser = parser +} + +// GetFileReader 获取全局文件读取器实例 +func GetFileReader() *FileReader { + return globalFileReader +} + +// SetFileReader 设置全局文件读取器实例 +func SetFileReader(reader *FileReader) { + globalFileReader = reader +} + +// ValidateIP 验证IP地址格式 +func ValidateIP(ip string) bool { + valid, _ := globalTargetParser.validateHost(ip) + return valid +} + +// ValidatePort 验证端口号 +func ValidatePort(port int) bool { + return port >= 1 && port <= 65535 +} + +// ValidatePortRange 验证端口范围 +func ValidatePortRange(startPort, endPort int) bool { + return ValidatePort(startPort) && ValidatePort(endPort) && startPort <= endPort +} + +// GetSupportedPortGroups 获取支持的端口组列表 +func GetSupportedPortGroups() []string { + return []string{"service", "db", "web", "all", "main"} +} + +// ExpandPortGroup 展开端口组 +func ExpandPortGroup(group string) string { + return globalTargetParser.expandPortGroups(group) +} + +// GetDefaultPorts 获取默认端口列表 +func GetDefaultPorts() string { + return globalTargetParser.options.DefaultPorts +} + +// SetDefaultPorts 设置默认端口列表 +func SetDefaultPorts(ports string) { + if globalTargetParser.options != nil { + globalTargetParser.options.DefaultPorts = ports + } +} + +// GetMaxTargets 获取最大目标数量限制 +func GetMaxTargets() int { + return globalTargetParser.options.MaxTargets +} + +// SetMaxTargets 设置最大目标数量限制 +func SetMaxTargets(max int) { + if globalTargetParser.options != nil { + globalTargetParser.options.MaxTargets = max + } +} \ No newline at end of file diff --git a/Common/parsers/TargetParser.go b/Common/parsers/TargetParser.go index 8e74284..b264ea6 100644 --- a/Common/parsers/TargetParser.go +++ b/Common/parsers/TargetParser.go @@ -43,7 +43,7 @@ func DefaultTargetParserOptions() *TargetParserOptions { ValidateURLs: true, ResolveDomains: false, EnableStatistics: true, - DefaultPorts: "80,443,22,21,23,25,53,110,993,995,1433,3306,5432,6379,27017", + 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", } } @@ -364,22 +364,48 @@ func (tp *TargetParser) parseHostList(hostStr string) ([]string, error) { continue } - // 检查是否为IP范围或CIDR - if strings.Contains(item, "/") { + // 检查各种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...) - } else if strings.Contains(item, "-") { - // IP范围表示法 + 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...) - } else { + default: // 单个IP或域名 hosts = append(hosts, item) } @@ -388,12 +414,15 @@ func (tp *TargetParser) parseHostList(hostStr string) ([]string, error) { return hosts, nil } -// parsePortList 解析端口列表 +// 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, ",") @@ -434,6 +463,22 @@ func (tp *TargetParser) parsePortList(portStr string) ([]int, error) { 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) @@ -442,46 +487,174 @@ func (tp *TargetParser) parseCIDR(cidr string) ([]string, error) { } var ips []string - ip := ipNet.IP.Mask(ipNet.Mask) + ip := make(net.IP, len(ipNet.IP)) + copy(ip, ipNet.IP) - for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); tp.nextIP(ip) { + count := 0 + for ipNet.Contains(ip) { ips = append(ips, ip.String()) + count++ // 防止生成过多IP - if len(ips) > tp.options.MaxTargets { + if count >= tp.options.MaxTargets { break } + + tp.nextIP(ip) } return ips, nil } -// parseIPRange 解析IP范围 +// 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地址") + 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) } - 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 + // 处理简写格式 (如: 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)) } } - ips = append(ips, endIP.String()) // 添加结束IP - return ips, nil + // 对其他二级网段进行稀疏采样 + 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 解析端口范围