mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
refactor: 重构ParseIP和ParsePort为模块化架构
将ParseIP.go和ParsePort.go的复杂解析逻辑迁移到parsers模块, 提供更好的错误处理、线程安全和功能扩展。 主要变更: - ParseIP.go: 从550行复杂实现重构为199行简洁包装层 - ParsePort.go: 从94行实现重构为33行简洁包装层 - 所有解析逻辑统一到parsers/TargetParser.go中 - 新增parsers/LegacyParser.go提供向后兼容接口 - 支持所有原有功能:IP范围、CIDR、网段简写、端口组等 - 完全保持API兼容性,无需修改调用代码 测试验证: - IP范围解析: 192.168.1.1-3 ✓ - 端口组展开: web → 210个端口 ✓ - CIDR和网段简写功能正常 ✓
This commit is contained in:
parent
5b1dde0a59
commit
f09bfdc346
@ -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)
|
||||
// 委托给新的parsers模块
|
||||
hosts, err = parsers.ParseIP(host, filename, nohosts...)
|
||||
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 != "") {
|
||||
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...)
|
||||
hosts, err := parsers.ParseIP(ipList, "")
|
||||
if err != nil {
|
||||
LogError(GetText("parse_ip_error") + ": " + err.Error())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else if ipList != "" {
|
||||
// 解析单个IP地址或范围
|
||||
result = parseSingleIP(ipList)
|
||||
}
|
||||
|
||||
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 // 简化版本
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
279
Common/parsers/LegacyParser.go
Normal file
279
Common/parsers/LegacyParser.go
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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, "-") {
|
||||
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]))
|
||||
startIPStr := strings.TrimSpace(parts[0])
|
||||
endIPStr := strings.TrimSpace(parts[1])
|
||||
|
||||
if startIP == nil || endIP == nil {
|
||||
return nil, fmt.Errorf("无效的IP地址")
|
||||
// 验证起始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())
|
||||
// 处理简写格式 (如: 192.168.1.1-100)
|
||||
if len(endIPStr) < 4 || !strings.Contains(endIPStr, ".") {
|
||||
return tp.parseShortIPRange(startIPStr, endIPStr)
|
||||
}
|
||||
|
||||
// 防止生成过多IP
|
||||
if len(ips) > tp.options.MaxTargets {
|
||||
break
|
||||
// 处理完整格式 (如: 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 解析端口范围
|
||||
|
Loading…
Reference in New Issue
Block a user